Ukubhala ikhowudi eguquguqukayo usebenzisa i-SOLID

Ukubhala ikhowudi eguquguqukayo usebenzisa i-SOLID

Isuka kumguquleli: ipapashelwe wena inqaku nguSeverin Perez malunga nokusebenzisa imigaqo ye-SOLID kucwangciso. Ulwazi oluvela kwinqaku luya kuba luncedo kubo bobabini abaqalayo kunye nabaprogram abanamava.

Ukuba ukwinkqubela phambili, kusenokwenzeka ukuba uvile ngemigaqo ye-SOLID. Benza ukuba umdwelisi wenkqubo abhale ikhowudi ecocekileyo, eyakheke kakuhle kwaye egcinwe lula. Kuyaphawuleka ukuba kwiprogramu kukho iindlela ezininzi zendlela yokwenza umsebenzi othile ngokuchanekileyo. Iingcali ezahlukeneyo zineembono ezahlukeneyo kunye nokuqonda "indlela elungileyo"; konke kuxhomekeke kumava omntu ngamnye. Nangona kunjalo, iingcamango ezivakaliswe kwi-SOLID zamkelwe phantse bonke abameli boluntu lwe-IT. Baye baba yindawo yokuqala yokuvela kunye nophuhliso lweendlela ezininzi zokulawula uphuhliso oluhle.

Masiqonde ukuba yintoni imigaqo-siseko ye-SOLID kwaye isinceda njani.

I-Skillbox iyacebisa: Ikhosi esebenzayo "UMqulunqi we-PRO".

Siyakhumbuza: kubo bonke abafundi be "Habr" - isaphulelo se-ruble ye-10 xa ubhalisa kuyo nayiphi na ikhosi ye-Skillbox usebenzisa ikhowudi yokuphromotha "Habr".

Yintoni i-SOLID?

Eli gama sisishunqulelo, unobumba ngamnye wekota sisiqalo segama lomgaqo othile:

  • SUMgaqo-siseko woXanduva. Imodyuli inokuba nesizathu esinye kunye nesinye kuphela sotshintsho.
  • The Oipeni/Umgaqo ovaliweyo (umgaqo ovuliweyo/ovaliweyo). Iiklasi kunye nezinye izinto kufuneka zivulelwe ukwandiswa, kodwa zivaliwe ukulungiswa.
  • β€ŠThe Liskov Substitution Principle (umgaqo wokutshintshwa kweLiskov). Imisebenzi esebenzisa uhlobo lwesiseko kufuneka ikwazi ukusebenzisa i-subtypes yohlobo lwesiseko ngaphandle kokwazi.
  • The II-Interface Segregation Principleβ€Š (umgaqo wokwahlula i-interface). Amaqumrhu esoftware akufuneki axhomekeke kwiindlela angazisebenzisiyo.
  • The Dependency Inversion Principle (umgaqo wokuxhomekeka kokuxhomekeka). Iimodyuli kumanqanaba aphezulu akufanele zixhomekeke kwiimodyuli kumanqanaba aphantsi.

UMgaqo woXanduva olunye

β€Š
ISingle Responsibility Principle (SRP) ichaza ukuba iklasi nganye okanye imodyuli kwiprogram kufuneka ibe noxanduva lwenxalenye enye kuphela yokusebenza kwaloo program. Ukongeza, imiba yolu xanduva kufuneka yabelwe iklasi yabo, kunokuba isasazwe kwiiklasi ezinganxulumananga. Umqambi we-SRP kunye nomvangeli oyintloko, uRobert S. Martin, uchaza uxanduva njengesizathu sokutshintsha. Ekuqaleni wayecebise eli gama njengenye yezinto eziphambili zomsebenzi wakhe "Imigaqo yoYilo oluJoliswe kwiNjongo". Ingqikelelo ibandakanya uninzi lwepateni yonxibelelwano eyayichazwe ngaphambili nguTom DeMarco.

Lo mbono wawuquka iikhonsepthi ezininzi eziqulunqwe nguDavid Parnas. Ezona zimbini ziphambili zi-encapsulation kunye nokufihla ulwazi. U-Parnas wathi ukwahlula inkqubo kwiimodyuli ezihlukeneyo akufanele kusekelwe kuhlalutyo lwemizobo yebhloko okanye ukuhamba kokubulawa. Naziphi na iimodyuli kufuneka ziqulathe isisombululo esithile esinika ubuncinci bolwazi kubaxhasi.

Ngendlela, uMartin wanikela umzekelo onomdla kunye nabaphathi abaphezulu benkampani (COO, CTO, CFO), ngamnye kubo usebenzisa isoftware ethile yeshishini ngeenjongo ezahlukeneyo. Ngenxa yoko, nayiphi na kubo inokuphumeza utshintsho kwisofthiwe ngaphandle kokuchaphazela umdla wabanye abaphathi.

Into yobuThixo

Njengesiqhelo, eyona ndlela ingcono yokufunda i-SRP kukuyibona isebenza. Masijonge icandelo lenkqubo ANGAlandeli uMgaqo woXanduva oluNye. Le yikhowudi yeRuby echaza indlela yokuziphatha kunye neempawu zesikhululo sendawo.

Hlaziya umzekelo uze uzame ukufumanisa oku kulandelayo:
Uxanduva lwezo zinto zibhengezwe kwiklasi ye-SpaceStation.
Abo banokuba nomdla ekusebenzeni kwesikhululo sasemajukujukwini.

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

Ngokwenyani, isitishi sethu sasemajukujukwini asisebenzi (andicingi ukuba ndiza kufumana umnxeba ovela kwi-NASA nanini na kungekudala), kodwa kukho into yokuhlalutya apha.

Ke, iklasi ye-SpaceStation ineemfanelo ezininzi ezahlukeneyo (okanye imisebenzi). Zonke zinokwahlulwa zibe ziindidi:

  • izixhobo zoluvo
  • izinto ezisetyenziswayo (izinto ezisetyenziswayo);
  • amafutha;
  • ii-accelerators.

Nangona kungekho namnye wabasebenzi besitishi wabelwa iklasi, sinokucinga ngokulula ukuba ngubani onoxanduva lwantoni. Okunokwenzeka, isazinzulu silawula abenzi boluvo, i-logistician inoxanduva lokubonelela ngezixhobo, injineli inoxanduva lokubonelela ngamafutha, kwaye umqhubi wenqwelomoya ulawula ii-boosters.

Ngaba sinokuthi le nkqubo ayihambelani ne-SRP? Ewe okuqinisekile. Kodwa iklasi ye-SpaceStation yinto eqhelekileyo "yothixo" owazi yonke into kwaye wenza yonke into. Le yipatheni enkulu echaseneyo nenkqubo ejolise kwizinto. Kubaqalayo, izinto ezinjalo zinzima kakhulu ukuzigcina. Ukuza kuthi ga ngoku inkqubo ilula kakhulu, ewe, kodwa khawucinge ukuba kuya kwenzeka ntoni ukuba songeza izinto ezintsha. Mhlawumbi isikhululo sethu sasemajukujukwini siya kufuna isikhululo sonyango okanye igumbi lentlanganiso. Kwaye imisebenzi emininzi ikhona, kokukhona i-SpaceStation iya kukhula. Ewe, kuba esi sixhobo siya kudityaniswa nabanye, ukusebenzela yonke indawo kuya kuba nzima ngakumbi. Ngenxa yoko, sinokuphazamisa ukusebenza, umzekelo, i-accelerators. Ukuba umphandi ucela utshintsho kwi-sensors, oku kunokuchaphazela kakuhle iinkqubo zonxibelelwano zesikhululo.

Ukuphula umgaqo we-SRP kunokunika uloyiso lwexesha elifutshane, kodwa ekugqibeleni siya "kulahlekelwa yimfazwe", kwaye kuya kuba nzima kakhulu ukugcina i-monster enjalo kwixesha elizayo. Kungcono ukwahlula inkqubo ibe ngamacandelo ahlukeneyo ekhowudi, elowo unoxanduva lokwenza umsebenzi othile. Ukuqonda oku, masitshintshe iklasi ye-SpaceStation.

Masabe uxanduva

Ngaphezulu sichaze iindidi ezine zokusebenza ezilawulwa yiklasi ye-SpaceStation. Siya kubagcina engqondweni xa siphinda silungisa. Ikhowudi ehlaziyiweyo ihambelana ngcono ne-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

Kukho utshintsho oluninzi, inkqubo ngokuqinisekileyo ibonakala ingcono ngoku. Ngoku iklasi yethu ye-SpaceStation iye yaba sisikhongozeli apho imisebenzi iqalwa khona kwiindawo ezixhomekeke kuzo, kubandakanywa iseti yezinzwa, inkqubo yonikezelo olusetyenziswayo, itanki yamafutha, kunye ne-boosters.

Kuyo nayiphi na into eguquguqukayo ngoku kukho udidi oluhambelanayo: IiSensors; SupplyHold; I-FuelTank; Ii-thrusters.

Kukho utshintsho oluninzi olubalulekileyo kolu guqulelo lwekhowudi. Ingongoma kukuba imisebenzi yomntu ngamnye ayifakwanga kuphela kwiiklasi zabo, icwangciswe ngendlela yokuba iqikeleleke kwaye ingaguquguquki. Sidibanisa izinto ezinomsebenzi ofanayo ukulandela umgaqo wokuhambelana. Ngoku, ukuba sifuna ukutshintsha indlela esebenza ngayo inkqubo, ukusuka kwisakhiwo se-hash ukuya kuluhlu, sebenzisa nje iklasi ye-SupplyHold; akufuneki sichukumise ezinye iimodyuli. Ngale ndlela, ukuba igosa lolungiselelo lolungiselelo litshintsha into ethile kwicandelo lalo, sonke isikhululo siya kuhlala sinjalo. Kule meko, iklasi ye-SpaceStation ayizukwazi notshintsho.

Amagosa ethu asebenza kwisikhululo sasemajukujukwini avuyiswa lutshintsho kuba ayakwazi ukucela ezo ayifunayo. Qaphela ukuba ikhowudi ineendlela ezifana ne-report_supplies kunye ne-report_fuel equlethwe kwiiklasi ze-SupplyHold kunye ne-FuelTank. Bekuya kwenzeka ntoni ukuba uMhlaba ubunokucela ukutshintsha indlela obika ngayo? Zombini iiklasi, i-SupplyHold kunye ne-FuelTank, kuya kufuneka zitshintshwe. Kuthekani ukuba ufuna ukutshintsha indlela amafutha kunye nezinto ezisetyenziswayo ezihanjiswayo? Kuya kufuneka ukuba utshintshe zonke iiklasi ezifanayo kwakhona. Kwaye oku sele kukwaphulwa komgaqo we-SRP. Masiyilungise lento.

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.

Kule nguqulo yakutshanje yeprogram, uxanduva luye lwahlulahlulwe lwaba ziiklasi ezimbini ezintsha, i-FuelReporter kunye ne-SupplyReporter. Bobabini ngabantwana beklasi yeNgxelo. Ukongeza, songeze umzekelo oguquguqukayo kwiklasi ye-SpaceStation ukuze i-subclass efunekayo iqaliswe ukuba kuyimfuneko. Ngoku, ukuba uMhlaba unquma ukutshintsha enye into, ngoko siya kwenza utshintsho kwii-subclasses, kwaye kungekhona kwiklasi eyintloko.

Kakade ke, ezinye iiklasi zethu zisaxhomekeke kwenye. Ngaloo ndlela, into ye-SupplyReporter ixhomekeke kwi-SupplyHold, kunye ne-FuelReporter ixhomekeke kwi-FuelTank. Ewe, ii-boosters kufuneka ziqhagamshelwe kwitanki yamafutha. Kodwa apha yonke into sele ibonakala isengqiqweni, kwaye ukwenza utshintsho akuyi kuba nzima kakhulu - ukuhlela ikhowudi yento enye akuyi kuchaphazela kakhulu enye.

Ngaloo ndlela, senze ikhowudi yemodyuli apho uxanduva lwento nganye / iiklasi zichazwe ngokuchanekileyo. Ukusebenza ngekhowudi enjalo akuyona ingxaki, ukuyigcina kuya kuba ngumsebenzi olula. Siguqule yonke "injongo kaThixo" kwi-SRP.

I-Skillbox iyacebisa:

umthombo: www.habr.com

Yongeza izimvo