Ke kākau ʻana i nā code maʻalahi me ka hoʻohana ʻana iā SOLID

Ke kākau ʻana i nā code maʻalahi me ka hoʻohana ʻana iā SOLID

Mai ka mea unuhi: paʻi ʻia no ʻoe ʻatikala na Severin Perez e pili ana i ka hoʻohana ʻana i nā loina SOLID i ka papahana. He mea pono ka ʻike mai ka ʻatikala i nā poʻe hoʻomaka a me nā mea papahana ʻike.

Inā ʻoe i ka hoʻomohala ʻana, ua lohe paha ʻoe i nā loina SOLID. Hāʻawi lākou i ka mea papahana e kākau i nā code maʻemaʻe, hoʻonohonoho maikaʻi ʻia a mālama maʻalahi. He mea pono e hoʻomaopopo i ka hoʻolālā ʻana he nui nā ala e hana pono ai i kahi hana. He ʻokoʻa nā manaʻo a me ka hoʻomaopopo ʻana o nā loea ʻokoʻa i ke "ala pololei"; pili ia i ka ʻike o kēlā me kēia kanaka. Eia naʻe, ʻae ʻia nā manaʻo i hoʻolaha ʻia ma SOLID e nā ʻelele āpau o ke kaiāulu IT. Ua lilo lākou i wahi hoʻomaka no ka puka ʻana a me ka hoʻomohala ʻana o nā hana hoʻokele hoʻomohala maikaʻi.

E hoʻomaopopo kākou i ke ʻano o nā loina SOLID a pehea e kōkua ai iā mākou.

Manaʻo ʻo Skillbox: Papa hana "Hoʻolālā Mobile PRO".

Hoʻomaopopo mākou iā ʻoe: no ka poʻe heluhelu a pau o "Habr" - kahi ho'ēmi o 10 rubles i ka wā e kākau inoa ai i kekahi papa Skillbox e hoʻohana ana i ka code promotional "Habr".

He aha ka SOLID?

He pōkole kēia huaʻōlelo, ʻo kēlā me kēia leka o ka huaʻōlelo ka hoʻomaka o ka inoa o kahi kumu kikoʻī.

  • SKumuhana Kuleana. Hiki i kekahi module ke loa'a ho'okahi kumu ho'ololi.
  • ka Openi/Kumu Paa (kumu hāmama/paʻa). Pono e wehe ʻia nā papa a me nā mea ʻē aʻe no ka hoʻonui ʻana, akā pani ʻia no ka hoʻololi ʻana.
  •  ka LKumu Hoʻololi iskov (Liskov hoʻololi kumu). Hiki i nā hana e hoʻohana ana i kahi ʻano kumu ke hoʻohana i nā subtypes o ke ʻano kumu me ka ʻike ʻole.
  • ka IKe Kumu Hoʻokaʻawale Interface  (kumu hoʻokaʻawale hoʻokaʻawale). ʻAʻole pono e hilinaʻi nā polokalamu lako polokalamu i nā ala a lākou e hoʻohana ʻole ai.
  • ka Dependency Inversion Principle (Principle of dependency inversion). ʻAʻole pono nā modula ma nā pae kiʻekiʻe ma luna o nā modula ma nā pae haʻahaʻa.

Kuʻuna Kuleana Hoʻokahi


Ua ʻōlelo ka Single Responsibility Principle (SRP) i kēlā me kēia papa a i ʻole module i loko o ka papahana ke kuleana no hoʻokahi wale nō ʻāpana o ka hana o ia papahana. Eia hou, pono e hāʻawi ʻia nā mea o kēia kuleana i kā lākou papa ponoʻī, ma mua o ka hoʻopuehu ʻana i nā papa pili ʻole. Ua wehewehe ʻo Robert S. Martin, ka mea hoʻomohala a me ka mea hoʻolaha nui o SRP, ke kumu o ka loli. Ua koho mua ʻo ia i kēia huaʻōlelo ʻo ia kekahi o nā mea o kāna hana "Principles of Object-Oriented Design". Hoʻokomo ka manaʻo i ka nui o ke ʻano hoʻohui i wehewehe mua ʻia e Tom DeMarco.

Ua komo pū ka manaʻo i kekahi mau manaʻo i haku ʻia e David Parnas. ʻO nā mea nui ʻelua ʻo ka encapsulation a me ka hūnā ʻike. Ua hoʻopaʻapaʻa ʻo Parnas ʻaʻole pono e hoʻokumu ʻia ka hoʻokaʻawale ʻana i kahi ʻōnaehana i nā modula ʻokoʻa i ka nānā ʻana i nā kiʻi poloka a i ʻole nā ​​kahe hoʻokō. Pono e loaʻa i kekahi o nā modules kahi hopena kikoʻī e hāʻawi i ka liʻiliʻi o ka ʻike i nā mea kūʻai aku.

Ma ke ala, ua hāʻawi ʻo Martin i kahi hiʻohiʻona hoihoi me nā luna kiʻekiʻe o kahi hui (COO, CTO, CFO), hoʻohana kēlā me kēia o lākou i nā polokalamu ʻoihana kūikawā no nā kumu like ʻole. ʻO ka hopena, hiki i kekahi o lākou ke hoʻokō i nā loli i ka polokalamu me ka ʻole o ka hoʻopilikia ʻana i nā pono o nā mana ʻē aʻe.

Mea akua

E like me nā manawa a pau, ʻo ke ala maikaʻi loa e aʻo ai iā SRP ʻo ka ʻike ʻana i ka hana. E nānā kākou i kahi ʻāpana o ka papahana ʻaʻole i hahai i ke Kumukānāwai Kuleana Hoʻokahi. ʻO kēia ka code Ruby e wehewehe ana i ka ʻano a me nā ʻano o ke kahua kikowaena.

E nānā i ka laʻana a e ho'āʻo e hoʻoholo i kēia:
Nā kuleana o kēlā mau mea i haʻi ʻia ma ka papa SpaceStation.
ʻO ka poʻe makemake paha i ka hana o ke kahua lewa.

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

ʻOiaʻiʻo, ʻaʻohe hana o kā mākou kahua kikowaena (ʻaʻole wau e manaʻo e loaʻa iaʻu kahi kelepona mai NASA i kēlā me kēia manawa), akā aia kahi mea e nānā ai ma aneʻi.

No laila, he mau kuleana like ʻole ka papa SpaceStation (a i ʻole nā ​​​​hana). Hiki ke hoʻokaʻawale ʻia lākou a pau i nā ʻano:

  • nā mea ʻike;
  • lako (mea hoʻohana);
  • wahie;
  • nā mea hoʻokē.

ʻOiai ʻaʻole i hāʻawi ʻia kekahi o nā limahana o ke kikowaena i kahi papa, hiki iā mākou ke noʻonoʻo maʻalahi i ka mea nona ke kuleana. ʻO ka mea maʻamau, ʻo ka ʻepekema ke hoʻomalu i nā mea ʻike, ʻo ka logistician ke kuleana no ka hoʻolako ʻana i nā kumuwaiwai, ke kuleana o ka ʻenekinia no nā lako wahie, a ʻo ka mea hoʻokele e hoʻokele i nā mea hoʻoikaika.

Hiki iā mākou ke ʻōlelo ʻaʻole kūpono kēia polokalamu iā SRP? ʻAe, maopopo. Akā ʻo ka papa SpaceStation kahi "mea akua" maʻamau i ʻike i nā mea āpau a hana i nā mea āpau. He ʻano anti-kūlana nui kēia i ka hoʻolālā ʻana i nā mea. No ka mea hoʻomaka, paʻakikī loa ka mālama ʻana i ia mau mea. I kēia manawa he maʻalahi loa ka papahana, ʻae, akā e noʻonoʻo i ka mea e hiki mai inā mākou e hoʻohui i nā hiʻohiʻona hou. Malia paha e pono ana ko mākou kahua kikowaena i ke keʻena lapaʻau a i ʻole ke keʻena hālāwai. A ʻoi aku ka nui o nā hana, ʻoi aku ka nui o ka SpaceStation e ulu. ʻAe, no ka mea e pili ana kēia hale i nā mea ʻē aʻe, ʻoi aku ka paʻakikī o ka lawelawe ʻana i ka paʻakikī holoʻokoʻa. ʻO ka hopena, hiki iā mākou ke hoʻopau i ka hana o, no ka laʻana, nā accelerators. Inā noi ka mea noiʻi i nā hoʻololi i nā mea ʻike, hiki i kēia ke hoʻopilikia maikaʻi i nā ʻōnaehana kamaʻilio o ke kikowaena.

ʻO ka hōʻole ʻana i ke kumumanaʻo SRP hiki ke hāʻawi i kahi lanakila maʻamau no ka manawa pōkole, akā i ka hopena e "nalo i ke kaua", a lilo ia i mea paʻakikī loa ka mālama ʻana i kēlā monster i ka wā e hiki mai ana. ʻOi aku ka maikaʻi o ka hoʻokaʻawale ʻana i ka papahana i nā ʻāpana ʻokoʻa o ke code, ʻo kēlā me kēia ke kuleana no ka hana ʻana i kahi hana kikoʻī. No ka hoʻomaopopo ʻana i kēia, e hoʻololi kākou i ka papa SpaceStation.

E puunaue kakou i ke kuleana

Ma luna aʻe ua wehewehe mākou i ʻehā ʻano hana i mālama ʻia e ka papa SpaceStation. E mālama mākou iā lākou i ka wā e hana hou ai. ʻOi aku ka maikaʻi o ke code hou i ka 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

Nui nā loli, ʻoi aku ka maikaʻi o ka papahana i kēia manawa. I kēia manawa ua lilo kā mākou papa SpaceStation i kahi pahu kahi e hoʻomaka ai nā hana no nā ʻāpana hilinaʻi, me kahi pūʻulu o nā mea ʻike, kahi ʻōnaehana lako hoʻohana, kahi pahu wahie, a me nā mea hoʻoikaika.

No kekahi o nā mea hoʻololi i kēia manawa he papa e pili ana: Sensors; SupplyHold; FuelTank; Nā mea hoʻolalelale.

Nui nā hoʻololi koʻikoʻi i kēia mana o ke code. ʻO ka manaʻo, ʻaʻole i hoʻopili wale ʻia nā hana o kēlā me kēia kanaka i kā lākou mau papa ponoʻī, ua hoʻonohonoho ʻia lākou i ke ʻano e hiki ke wānana a kūlike. Hoʻopili mākou i nā mea me nā hana like e hahai i ke kumu o ka coherence. I kēia manawa, inā pono mākou e hoʻololi i ke ʻano o ka hana ʻana o ka ʻōnaehana, e neʻe ana mai kahi hoʻolālā hash i kahi array, e hoʻohana wale i ka papa SupplyHold; ʻaʻole pono mākou e hoʻopā i nā modula ʻē aʻe. ʻO kēia ala, inā hoʻololi ka luna logistic i kekahi mea ma kāna ʻāpana, e paʻa mau ke koena o ke kikowaena. I kēia hihia, ʻaʻole ʻike ka papa SpaceStation i nā loli.

Hauʻoli paha kā mākou mau luna e hana ana ma ke kahua lewa i nā loli no ka mea hiki iā lākou ke noi i nā mea e pono ai lākou. E hoʻomaopopo he loaʻa nā ʻano o ke code e like me report_supplies a me report_fuel i loko o nā papa SupplyHold a me FuelTank. He aha ka hopena inā noi ka Honua e hoʻololi i ke ʻano o kāna hōʻike? Pono e hoʻololi ʻia nā papa ʻelua, SupplyHold a me FuelTank. He aha inā pono ʻoe e hoʻololi i ke ʻano o ka lawe ʻia ʻana o ka wahie a me nā mea hoʻohana? Pono paha ʻoe e hoʻololi hou i nā papa like a pau. A ua hewa kēia i ke kumu SRP. E hoʻoponopono kākou i kēia.

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.

Ma kēia mana hou o ka papahana, ua māhele ʻia nā kuleana i ʻelua papa hou, FuelReporter a me SupplyReporter. He mau keiki lāua o ka papa Reporter. Eia hou, ua hoʻohui mākou i nā mea hoʻololi i ka papa SpaceStation i hiki ke hoʻomaka i ka subclass i makemake ʻia inā pono. I kēia manawa, inā hoʻoholo ka Honua e hoʻololi i kahi mea ʻē aʻe, a laila e hoʻololi mākou i nā subclasses, ʻaʻole i ka papa nui.

ʻOiaʻiʻo, ke hilinaʻi nei kekahi o kā mākou papa i kekahi i kekahi. No laila, pili ka mea SupplyReporter ma SupplyHold, a hilinaʻi ʻo FuelReporter iā FuelTank. ʻOiaʻiʻo, pono e hoʻopili ʻia nā mea hoʻoikaika i ka pahu wahie. Akā eia nā mea a pau ke nānā pono nei, a ʻaʻole paʻakikī loa ka hoʻololi ʻana - ʻo ka hoʻoponopono ʻana i ke code o kekahi mea ʻaʻole e pili nui i kekahi.

No laila, ua hana mākou i kahi code modular kahi i wehewehe pono ʻia ai nā kuleana o kēlā me kēia mea / papa. ʻAʻole pilikia ka hana ʻana me ia code, ʻo ka mālama ʻana he hana maʻalahi. Ua hoʻololi mākou i ka "mea haipule" holoʻokoʻa i SRP.

Manaʻo ʻo Skillbox:

Source: www.habr.com

Pākuʻi i ka manaʻo hoʻopuka