Kikọ koodu to rọ ni lilo SOLID

Kikọ koodu to rọ ni lilo SOLID

Lati ọdọ onitumọ: atejade fun o article nipa Severin Perez nipa lilo awọn ilana SOLID ni siseto. Alaye lati inu nkan naa yoo wulo fun awọn olubere mejeeji ati awọn olupilẹṣẹ ti o ni iriri.

Ti o ba wa sinu idagbasoke, o ṣee ṣe julọ ti gbọ ti awọn ipilẹ SOLID. Wọn jẹ ki olupilẹṣẹ ṣiṣẹ lati kọ mimọ, ti iṣeto daradara ati koodu mimu ni irọrun. O tọ lati ṣe akiyesi pe ni siseto awọn ọna pupọ wa si bii o ṣe le ṣe deede iṣẹ kan pato. Awọn alamọja oriṣiriṣi ni awọn imọran oriṣiriṣi ati oye ti “ọna ti o tọ”; gbogbo rẹ da lori iriri eniyan kọọkan. Sibẹsibẹ, awọn imọran ti a kede ni SOLID jẹ itẹwọgba nipasẹ fere gbogbo awọn aṣoju ti agbegbe IT. Wọn di aaye ibẹrẹ fun ifarahan ati idagbasoke ti ọpọlọpọ awọn ilana iṣakoso idagbasoke ti o dara.

Jẹ ki a loye kini awọn ipilẹ SOLID jẹ ati bii wọn ṣe ṣe iranlọwọ fun wa.

Skillbox ṣe iṣeduro: Ilana ti o wulo "Olugbese Alagbeka PRO".

A leti: fun gbogbo awọn oluka ti "Habr" - ẹdinwo ti 10 rubles nigbati o forukọsilẹ ni eyikeyi iṣẹ-ẹkọ Skillbox nipa lilo koodu ipolowo “Habr”.

Kini SOLID?

Oro yii jẹ abbreviation, lẹta kọọkan ti ọrọ naa jẹ ibẹrẹ ti orukọ ti ilana kan pato:

  • Single Ojúṣe Ilana. A module le ni ọkan ati ki o nikan idi kan fun ayipada.
  • awọn Oikọwe / Pipade Ilana (ìmọ / pipade opo). Awọn kilasi ati awọn eroja miiran yẹ ki o ṣii fun itẹsiwaju, ṣugbọn pipade fun iyipada.
  •  awọn Liskov Fidipo Ilana (Liskov fidipo opo). Awọn iṣẹ ti o lo iru ipilẹ yẹ ki o ni anfani lati lo awọn subtypes ti iru ipilẹ laisi mimọ.
  • awọn INi wiwo Iyapa Ilana  (interface Iyapa opo). Awọn ohun elo sọfitiwia ko yẹ ki o dale lori awọn ọna ti wọn ko lo.
  • awọn DEpendency Inversion Ilana (ilana ti gbára inversion). Awọn modulu ni awọn ipele giga ko yẹ ki o dale lori awọn modulu ni awọn ipele kekere.

Ilana Ojuse Kanṣo


Ilana Ojuse Kanṣo (SRP) sọ pe kilasi kọọkan tabi module ninu eto yẹ ki o jẹ iduro fun apakan kan nikan ti iṣẹ ṣiṣe eto naa. Ni afikun, awọn eroja ti ojuse yii yẹ ki o pin si kilasi tiwọn, dipo ki o tuka kaakiri awọn kilasi ti ko ni ibatan. Olùgbéejáde SRP ati ajíhìnrere agba, Robert S. Martin, ṣe àpèjúwe ìjíhìn gẹ́gẹ́ bí ìdí fún ìyípadà. Ni akọkọ o dabaa ọrọ yii gẹgẹbi ọkan ninu awọn eroja ti iṣẹ rẹ "Awọn ilana ti Apẹrẹ-Oorun Nkan". Agbekale naa ṣafikun pupọ julọ ilana ọna asopọ ti Tom DeMarco ti ṣalaye tẹlẹ.

Agbekale naa tun pẹlu awọn imọran pupọ ti David Parnas ṣe agbekalẹ. Awọn akọkọ meji jẹ fifipamọ ati fifipamọ alaye. Parnas jiyan pe pinpin eto kan si awọn modulu lọtọ ko yẹ ki o da lori igbekale awọn aworan atọka tabi awọn ṣiṣan ipaniyan. Eyikeyi ninu awọn modulu gbọdọ ni ojutu kan pato ti o pese alaye ti o kere ju si awọn alabara.

Nipa ọna, Martin fun apẹẹrẹ ti o nifẹ pẹlu awọn alakoso agba ti ile-iṣẹ kan (COO, CTO, CFO), ọkọọkan wọn nlo sọfitiwia iṣowo kan pato fun awọn idi oriṣiriṣi. Bi abajade, eyikeyi ninu wọn le ṣe awọn ayipada ninu sọfitiwia laisi ni ipa awọn iwulo ti awọn alakoso miiran.

Atorunwa ohun

Gẹgẹbi nigbagbogbo, ọna ti o dara julọ lati kọ ẹkọ SRP ni lati rii ni iṣe. Jẹ ki a wo apakan ti eto naa ti KO tẹle Ilana Ojuse Kanṣoṣo. Eyi jẹ koodu Ruby ti o ṣe apejuwe ihuwasi ati awọn abuda ti ibudo aaye naa.

Ṣayẹwo apẹẹrẹ naa ki o gbiyanju lati pinnu atẹle naa:
Awọn ojuṣe ti awọn nkan wọnyẹn ti a kede ni kilasi SpaceStation.
Awọn ti o le nifẹ si iṣẹ ti ibudo aaye naa.

class SpaceStation
  def initialize
    @supplies = {}
    @fuel = 0
  end
 
  def run_sensors
    puts "----- Sensor Action -----"
    puts "Running sensors!"
  end
 
  def load_supplies(type, quantity)
    puts "----- Supply Action -----"
    puts "Loading #{quantity} units of #{type} in the supply hold."
    
    if @supplies[type]
      @supplies[type] += quantity
    else
      @supplies[type] = quantity
    end
  end
 
  def use_supplies(type, quantity)
    puts "----- Supply Action -----"
    if @supplies[type] != nil && @supplies[type] > quantity
      puts "Using #{quantity} of #{type} from the supply hold."
      @supplies[type] -= quantity
    else
      puts "Supply Error: Insufficient #{type} in the supply hold."
    end
  end
 
  def report_supplies
    puts "----- Supply Report -----"
    if @supplies.keys.length > 0
      @supplies.each do |type, quantity|
        puts "#{type} avalilable: #{quantity} units"
      end
    else
      puts "Supply hold is empty."
    end
  end
 
  def load_fuel(quantity)
    puts "----- Fuel Action -----"
    puts "Loading #{quantity} units of fuel in the tank."
    @fuel += quantity
  end
 
  def report_fuel
    puts "----- Fuel Report -----"
    puts "#{@fuel} units of fuel available."
  end
 
  def activate_thrusters
    puts "----- Thruster Action -----"
    if @fuel >= 10
      puts "Thrusting action successful."
      @fuel -= 10
    else
      puts "Thruster Error: Insufficient fuel available."
    end
  end
end

Lootọ, aaye aaye wa ko ṣiṣẹ (Emi ko ro pe Emi yoo gba ipe lati ọdọ NASA nigbakugba laipẹ), ṣugbọn nkankan wa lati ṣe itupalẹ nibi.

Nitorinaa, kilasi SpaceStation ni ọpọlọpọ awọn ojuse oriṣiriṣi (tabi awọn iṣẹ ṣiṣe). Gbogbo wọn le pin si awọn oriṣi:

  • awọn sensọ;
  • awọn ohun elo (awọn ohun elo);
  • idana;
  • accelerators.

Paapaa botilẹjẹpe ko si ọkan ninu awọn oṣiṣẹ ibudo ti o yan kilasi kan, a le ni irọrun fojuinu ẹni ti o ṣe iduro fun kini. O ṣeese julọ, onimọ-jinlẹ n ṣakoso awọn sensọ, onimọ-jinlẹ jẹ iduro fun ipese awọn orisun, ẹlẹrọ jẹ iduro fun awọn ipese epo, ati awakọ n ṣakoso awọn igbelaruge.

Njẹ a le sọ pe eto yii ko ni ibamu pẹlu SRP? Beeni. Ṣugbọn kilasi SpaceStation jẹ aṣoju “ohun ọlọrun” ti o mọ ohun gbogbo ti o ṣe ohun gbogbo. Eyi jẹ apẹrẹ atako pataki kan ninu siseto ti o da lori ohun. Fun olubere, iru awọn nkan jẹ gidigidi soro lati ṣetọju. Nitorinaa eto naa rọrun pupọ, bẹẹni, ṣugbọn fojuinu kini yoo ṣẹlẹ ti a ba ṣafikun awọn ẹya tuntun. Boya ibudo aaye wa yoo nilo ibudo iṣoogun tabi yara ipade kan. Ati pe awọn iṣẹ diẹ sii wa, diẹ sii SpaceStation yoo dagba. O dara, niwọn igba ti ohun elo yii yoo ni asopọ si awọn miiran, ṣiṣe iṣẹ gbogbo eka naa yoo di idiju paapaa. Bi abajade, a le dabaru iṣẹ ti, fun apẹẹrẹ, awọn accelerators. Ti oluwadii kan ba beere awọn iyipada si awọn sensọ, eyi le ni ipa gaan awọn eto ibaraẹnisọrọ ibudo naa.

Ti o ṣẹ ilana SRP le funni ni iṣẹgun ọgbọn igba kukuru, ṣugbọn ni ipari a yoo “padanu ogun”, ati pe yoo nira pupọ lati ṣetọju iru aderubaniyan ni ọjọ iwaju. O dara julọ lati pin eto naa si awọn apakan lọtọ ti koodu, ọkọọkan eyiti o jẹ iduro fun ṣiṣe iṣẹ kan pato. Ni oye eyi, jẹ ki a yi kilasi SpaceStation pada.

Jẹ ki a pin ojuse

Loke a ti ṣalaye awọn iru iṣẹ mẹrin ti kilasi SpaceStation jẹ iṣakoso. A yoo pa wọn ni lokan nigba refactoring. Awọn imudojuiwọn koodu dara ibaamu awọn SRP.

class SpaceStation
  attr_reader :sensors, :supply_hold, :fuel_tank, :thrusters
 
  def initialize
    @supply_hold = SupplyHold.new
    @sensors = Sensors.new
    @fuel_tank = FuelTank.new
    @thrusters = Thrusters.new(@fuel_tank)
  end
end
 
class Sensors
  def run_sensors
    puts "----- Sensor Action -----"
    puts "Running sensors!"
  end
end
 
class SupplyHold
  attr_accessor :supplies
 
  def initialize
    @supplies = {}
  end
 
  def load_supplies(type, quantity)
    puts "----- Supply Action -----"
    puts "Loading #{quantity} units of #{type} in the supply hold."
    
    if @supplies[type]
      @supplies[type] += quantity
    else
      @supplies[type] = quantity
    end
  end
 
  def use_supplies(type, quantity)
    puts "----- Supply Action -----"
    if @supplies[type] != nil && @supplies[type] > quantity
      puts "Using #{quantity} of #{type} from the supply hold."
      @supplies[type] -= quantity
    else
      puts "Supply Error: Insufficient #{type} in the supply hold."
    end
  end
 
  def report_supplies
    puts "----- Supply Report -----"
    if @supplies.keys.length > 0
      @supplies.each do |type, quantity|
        puts "#{type} avalilable: #{quantity} units"
      end
    else
      puts "Supply hold is empty."
    end
  end
end
 
class FuelTank
  attr_accessor :fuel
 
  def initialize
    @fuel = 0
  end
 
  def get_fuel_levels
    @fuel
  end
 
  def load_fuel(quantity)
    puts "----- Fuel Action -----"
    puts "Loading #{quantity} units of fuel in the tank."
    @fuel += quantity
  end
 
  def use_fuel(quantity)
    puts "----- Fuel Action -----"
    puts "Using #{quantity} units of fuel from the tank."
    @fuel -= quantity
  end
 
  def report_fuel
    puts "----- Fuel Report -----"
    puts "#{@fuel} units of fuel available."
  end
end
 
class Thrusters
  def initialize(fuel_tank)
    @linked_fuel_tank = fuel_tank
  end
 
  def activate_thrusters
    puts "----- Thruster Action -----"
    if @linked_fuel_tank.get_fuel_levels >= 10
      puts "Thrusting action successful."
      @linked_fuel_tank.use_fuel(10)
    else
      puts "Thruster Error: Insufficient fuel available."
    end
  end
end

Awọn ayipada pupọ wa, dajudaju eto naa dara julọ ni bayi. Bayi kilasi SpaceStation wa ti di diẹ sii ti apo kan ninu eyiti awọn iṣẹ ṣiṣe ti bẹrẹ fun awọn ẹya ti o gbẹkẹle, pẹlu ṣeto awọn sensọ, eto ipese agbara, ojò epo, ati awọn olupolowo.

Fun eyikeyi ninu awọn oniyipada o wa ni bayi kilasi ti o baamu: Awọn sensọ; Idaduro Ipese; Epo epo; Thrusters.

Awọn ayipada pataki pupọ lo wa ninu ẹya koodu yii. Oro naa ni pe awọn iṣẹ-ṣiṣe kọọkan ko ni fifẹ nikan ni awọn kilasi ti ara wọn, wọn ti ṣeto ni ọna ti o le di asọtẹlẹ ati ni ibamu. A ṣe akojọpọ awọn eroja pẹlu iṣẹ ṣiṣe ti o jọra lati tẹle ilana ti isomọ. Ni bayi, ti a ba nilo lati yi ọna ti eto naa ṣiṣẹ, gbigbe lati ọna hash kan si opo kan, kan lo kilasi Ipese; a ko ni lati fi ọwọ kan awọn modulu miiran. Ni ọna yii, ti oṣiṣẹ eekaderi ba yipada nkan ni apakan rẹ, iyoku ibudo naa yoo wa ni mimule. Ni ọran yii, kilasi SpaceStation kii yoo paapaa mọ awọn iyipada.

Awọn oṣiṣẹ wa ti n ṣiṣẹ lori ibudo aaye ni o ṣee ṣe inudidun nipa awọn iyipada nitori wọn le beere awọn ti wọn nilo. Ṣe akiyesi pe koodu naa ni awọn ọna bii report_supplies ati report_fuel ti o wa ninu awọn kilasi SupplyHold ati FuelTank. Kini yoo ṣẹlẹ ti Earth ba beere lati yi ọna ti o ṣe ijabọ pada? Awọn kilasi mejeeji, IpeseHold ati FuelTank, yoo nilo lati yipada. Kini ti o ba nilo lati yi ọna ti a fi jiṣẹ epo ati awọn ohun elo pada? O ṣee ṣe pe iwọ yoo ni lati yi gbogbo awọn kilasi kanna pada lẹẹkansi. Ati pe eyi ti jẹ irufin ilana SRP tẹlẹ. Jẹ ki a ṣatunṣe eyi.

class SpaceStation
  attr_reader :sensors, :supply_hold, :supply_reporter,
              :fuel_tank, :fuel_reporter, :thrusters
 
  def initialize
    @sensors = Sensors.new
    @supply_hold = SupplyHold.new
    @supply_reporter = SupplyReporter.new(@supply_hold)
    @fuel_tank = FuelTank.new
    @fuel_reporter = FuelReporter.new(@fuel_tank)
    @thrusters = Thrusters.new(@fuel_tank)
  end
end
 
class Sensors
  def run_sensors
    puts "----- Sensor Action -----"
    puts "Running sensors!"
  end
end
 
class SupplyHold
  attr_accessor :supplies
  attr_reader :reporter
 
  def initialize
    @supplies = {}
  end
 
  def get_supplies
    @supplies
  end
 
  def load_supplies(type, quantity)
    puts "----- Supply Action -----"
    puts "Loading #{quantity} units of #{type} in the supply hold."
    
    if @supplies[type]
      @supplies[type] += quantity
    else
      @supplies[type] = quantity
    end
  end
 
  def use_supplies(type, quantity)
    puts "----- Supply Action -----"
    if @supplies[type] != nil && @supplies[type] > quantity
      puts "Using #{quantity} of #{type} from the supply hold."
      @supplies[type] -= quantity
    else
      puts "Supply Error: Insufficient #{type} in the supply hold."
    end
  end
end
 
class FuelTank
  attr_accessor :fuel
  attr_reader :reporter
 
  def initialize
    @fuel = 0
  end
 
  def get_fuel_levels
    @fuel
  end
 
  def load_fuel(quantity)
    puts "----- Fuel Action -----"
    puts "Loading #{quantity} units of fuel in the tank."
    @fuel += quantity
  end
 
  def use_fuel(quantity)
    puts "----- Fuel Action -----"
    puts "Using #{quantity} units of fuel from the tank."
    @fuel -= quantity
  end
end
 
class Thrusters
  FUEL_PER_THRUST = 10
 
  def initialize(fuel_tank)
    @linked_fuel_tank = fuel_tank
  end
 
  def activate_thrusters
    puts "----- Thruster Action -----"
    
    if @linked_fuel_tank.get_fuel_levels >= FUEL_PER_THRUST
      puts "Thrusting action successful."
      @linked_fuel_tank.use_fuel(FUEL_PER_THRUST)
    else
      puts "Thruster Error: Insufficient fuel available."
    end
  end
end
 
class Reporter
  def initialize(item, type)
    @linked_item = item
    @type = type
  end
 
  def report
    puts "----- #{@type.capitalize} Report -----"
  end
end
 
class FuelReporter < Reporter
  def initialize(item)
    super(item, "fuel")
  end
 
  def report
    super
    puts "#{@linked_item.get_fuel_levels} units of fuel available."
  end
end
 
class SupplyReporter < Reporter
  def initialize(item)
    super(item, "supply")
  end
 
  def report
    super
    if @linked_item.get_supplies.keys.length > 0
      @linked_item.get_supplies.each do |type, quantity|
        puts "#{type} avalilable: #{quantity} units"
      end
    else
      puts "Supply hold is empty."
    end
  end
end
 
iss = SpaceStation.new
 
iss.sensors.run_sensors
  # ----- Sensor Action -----
  # Running sensors!
 
iss.supply_hold.use_supplies("parts", 2)
  # ----- Supply Action -----
  # Supply Error: Insufficient parts in the supply hold.
iss.supply_hold.load_supplies("parts", 10)
  # ----- Supply Action -----
  # Loading 10 units of parts in the supply hold.
iss.supply_hold.use_supplies("parts", 2)
  # ----- Supply Action -----
  # Using 2 of parts from the supply hold.
iss.supply_reporter.report
  # ----- Supply Report -----
  # parts avalilable: 8 units
 
iss.thrusters.activate_thrusters
  # ----- Thruster Action -----
  # Thruster Error: Insufficient fuel available.
iss.fuel_tank.load_fuel(100)
  # ----- Fuel Action -----
  # Loading 100 units of fuel in the tank.
iss.thrusters.activate_thrusters
  # ----- Thruster Action -----
  # Thrusting action successful.
  # ----- Fuel Action -----
  # Using 10 units of fuel from the tank.
iss.fuel_reporter.report
  # ----- Fuel Report -----
# 90 units of fuel available.

Ninu ẹya tuntun ti eto naa, awọn ojuse ti pin si awọn kilasi tuntun meji, FuelReporter ati SupplyReporter. Awon mejeeji ni omo egbe Oniroyin. Ni afikun, a ṣafikun awọn oniyipada apẹẹrẹ si kilasi SpaceStation ki ipin ti o fẹ le ṣe ipilẹṣẹ ti o ba jẹ dandan. Bayi, ti Earth ba pinnu lati yi nkan miiran pada, lẹhinna a yoo ṣe awọn ayipada si awọn kilasi kekere, kii ṣe si kilasi akọkọ.

Dajudaju, diẹ ninu awọn kilasi wa tun dale lori ara wọn. Nitorinaa, ohun Ipese Olupese da lori SupplyHold, ati FuelReporter da lori FuelTank. Dajudaju, awọn igbelaruge gbọdọ wa ni asopọ si epo epo. Ṣugbọn nibi ohun gbogbo ti dabi ọgbọn, ati ṣiṣe awọn ayipada kii yoo nira ni pataki - ṣiṣatunṣe koodu ohun kan kii yoo ni ipa miiran pupọ.

Nitorinaa, a ti ṣẹda koodu apọjuwọn nibiti awọn ojuse ti ọkọọkan awọn nkan / kilasi jẹ asọye ni pipe. Ṣiṣẹ pẹlu iru koodu kii ṣe iṣoro, mimu yoo jẹ iṣẹ ti o rọrun. A ti yi gbogbo “ohun ti Ọlọrun” pada si SRP.

Skillbox ṣe iṣeduro:

orisun: www.habr.com

Fi ọrọìwòye kun