Sau cov lej hloov tau siv SOLID

Sau cov lej hloov tau siv SOLID

Los ntawm tus txhais lus: luam tawm rau koj tsab xov xwm los ntawm Severin Perez hais txog kev siv SOLID cov hauv paus ntsiab lus hauv programming. Cov ntaub ntawv los ntawm tsab xov xwm yuav pab tau rau ob qho tib si beginners thiab tej programmers.

Yog tias koj nkag mus rau hauv kev txhim kho, koj feem ntau yuav hnov ​​​​txog cov ntsiab lus SOLID. Lawv pab kom tus programmer sau cov ntawv huv, zoo tsim thiab tswj tau yooj yim. Nws yog ib nqi sau cia hais tias nyob rau hauv lub programming muaj ob peb txoj kev yuav ua li cas kom raug ua ib txoj hauj lwm. Cov kws tshaj lij sib txawv muaj cov tswv yim sib txawv thiab kev nkag siab ntawm "txoj kev raug"; nws tag nrho nyob ntawm txhua tus neeg txoj kev paub. Txawm li cas los xij, cov tswv yim tshaj tawm hauv SOLID tau txais los ntawm yuav luag txhua tus neeg sawv cev ntawm IT zej zog. Lawv tau los ua qhov pib ntawm qhov tshwm sim thiab kev loj hlob ntawm ntau yam kev txhim kho kev tswj hwm kev ua haujlwm zoo.

Cia peb nkag siab tias cov ntsiab lus SOLID yog dab tsi thiab lawv pab peb li cas.

Skillbox pom zoo: Cov chav kawm siv tau "Mobile Developer PRO".

Peb nco qab: rau txhua tus neeg nyeem Habr - 10 ruble luv nqi thaum tso npe rau hauv ib chav kawm Skillbox siv Habr promo code.

SOLID yog dab tsi?

Lub sij hawm no yog ib qho luv luv, txhua tsab ntawv ntawm lub sij hawm yog qhov pib ntawm lub npe ntawm lub hauv paus ntsiab lus tshwj xeeb:

  • Single Lub Luag Haujlwm Txoj Cai. Ib qho module tuaj yeem muaj ib qho thiab tsuas yog ib qho laj thawj rau kev hloov pauv.
  • cov Ocwj mem/Closed Principple (qhib / kaw txoj cai). Cov chav kawm thiab lwm yam yuav tsum qhib rau kev txuas ntxiv, tab sis kaw rau kev hloov kho.
  • β€Šcov Liskov Hloov Txoj Cai (Liskov hloov txoj cai). Cov haujlwm uas siv lub hauv paus hom yuav tsum siv cov subtypes ntawm lub hauv paus yam tsis paub txog.
  • cov IInterface Segregation Princippleβ€Š (interface cais txoj cai). Cov koom haum software yuav tsum tsis txhob nyob ntawm txoj kev uas lawv tsis siv.
  • cov Dependency Inversion Txoj Cai (txoj cai ntawm kev vam meej inversion). Modules ntawm qib siab yuav tsum tsis txhob nyob ntawm cov modules ntawm qib qis.

Lub Luag Haujlwm Ib Leeg

β€Š
Txoj Cai Tswjfwm Ib Leeg Lub Luag Haujlwm (SRP) hais tias txhua chav kawm lossis cov qauv hauv ib qho kev pabcuam yuav tsum muaj lub luag haujlwm tsuas yog ib feem ntawm qhov haujlwm ntawd. Tsis tas li ntawd, cov ntsiab lus ntawm lub luag haujlwm no yuav tsum tau muab rau lawv tus kheej hauv chav kawm, tsis yog nyob rau hauv cov chav kawm uas tsis muaj kev cuam tshuam. SRP tus tsim tawm thiab tus thawj coj tshaj tawm txoj moo zoo, Robert S. Martin, piav qhia txog kev lav phib xaub vim qhov hloov pauv. Nws Ameslikas tau muab lo lus no los ua ib qho ntawm nws txoj haujlwm "Principles of Object-Oriented Design". Lub tswv yim suav nrog ntau ntawm cov qauv kev sib txuas uas yav dhau los tau txhais los ntawm Tom DeMarco.

Lub tswv yim kuj suav nrog ntau lub tswv yim tsim los ntawm David Parnas. Ob qho tseem ceeb yog encapsulation thiab cov ntaub ntawv zais. Parnas tau sib cav hais tias kev faib cov txheej txheem rau hauv cov qauv sib cais yuav tsum tsis txhob ua raws li kev txheeb xyuas ntawm daim duab thaiv lossis kev ua tiav. Ib qho ntawm cov modules yuav tsum muaj cov kev daws teeb meem tshwj xeeb uas muab cov ntaub ntawv yam tsawg kawg nkaus rau cov neeg siv khoom.

Los ntawm txoj kev, Martin tau muab ib qho piv txwv nthuav nrog cov thawj coj loj ntawm lub tuam txhab (COO, CTO, CFO), txhua tus neeg siv cov software tshwj xeeb rau cov hom phiaj sib txawv. Yog li ntawd, ib qho ntawm lawv tuaj yeem siv cov kev hloov pauv hauv software yam tsis muaj kev cuam tshuam rau kev nyiam ntawm lwm tus thawj tswj hwm.

Divine khoom

Raws li ib txwm muaj, txoj hauv kev zoo tshaj plaws los kawm SRP yog pom nws ua haujlwm. Cia peb saib ib ntu ntawm qhov kev zov me nyuam uas TSIS ua raws li Txoj Cai Tswjfwm Ib Leeg. Qhov no yog Ruby code uas piav qhia txog tus cwj pwm thiab cov cwj pwm ntawm qhov chaw nres tsheb.

Tshawb xyuas qhov piv txwv thiab sim txiav txim siab hauv qab no:
Lub luag haujlwm ntawm cov khoom uas tau tshaj tawm hauv chav kawm SpaceStation.
Cov neeg uas yuav txaus siab rau kev ua haujlwm ntawm qhov chaw nres tsheb.

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

Qhov tseeb, peb qhov chaw nres tsheb tsis zoo (Kuv tsis xav tias kuv yuav tau txais kev hu xovtooj los ntawm NASA txhua lub sijhawm sai sai), tab sis muaj qee yam los tshuaj xyuas ntawm no.

Yog li, chav kawm SpaceStation muaj ntau lub luag haujlwm sib txawv (lossis ua haujlwm). Tag nrho lawv tuaj yeem muab faib ua hom:

  • sensors;
  • khoom siv (consumables);
  • roj;
  • accelerators.

Txawm hais tias tsis muaj ib lub chaw nres tsheb cov neeg ua haujlwm raug xaiv ib chav kawm, peb tuaj yeem yooj yim xav txog seb leej twg yog tus lav ris rau dab tsi. Feem ntau, tus kws tshawb fawb tswj cov sensors, tus neeg tsav tsheb yog lub luag haujlwm rau kev muab cov khoom siv, tus engineer yog lub luag haujlwm rau cov khoom siv roj, thiab tus tsav tsheb tswj cov boosters.

Peb puas tuaj yeem hais tias qhov program no tsis ua raws li SRP? Yog, tseeb. Tab sis chav kawm SpaceStation yog ib qho "vajtswv khoom" uas paub txhua yam thiab ua txhua yam. Qhov no yog ib qho kev tawm tsam loj hauv cov phiaj xwm kev taw qhia. Rau ib tug beginner, xws li cov khoom yog heev nyuaj rau tswj. Txog tam sim no qhov kev pab cuam yooj yim heev, yog, tab sis xav txog yuav ua li cas yog tias peb ntxiv cov yam ntxwv tshiab. Tej zaum peb qhov chaw nres tsheb yuav xav tau chaw kho mob lossis chav sib tham. Thiab ntau lub zog muaj, ntau qhov SpaceStation yuav loj tuaj. Zoo, txij li qhov chaw no yuav txuas nrog rau lwm tus, kev pabcuam tag nrho txoj haujlwm yuav nyuaj dua. Yog li ntawd, peb tuaj yeem cuam tshuam kev ua haujlwm ntawm, piv txwv li, accelerators. Yog tias tus kws tshawb fawb thov hloov pauv cov sensors, qhov no tuaj yeem cuam tshuam zoo rau lub chaw nres tsheb cov kev sib txuas lus.

Kev ua txhaum cai ntawm SRP yuav ua rau lub sijhawm luv luv tactical yeej, tab sis thaum kawg peb yuav "poob tsov rog", thiab nws yuav nyuaj heev los tuav tus dab zoo li no yav tom ntej. Nws yog qhov zoo tshaj plaws los faib qhov kev zov me nyuam rau hauv cov kab ke sib cais, txhua tus yog lub luag haujlwm rau kev ua haujlwm tshwj xeeb. To taub qhov no, cia peb hloov chav kawm SpaceStation.

Cia peb faib lub luag haujlwm

Saum toj no peb tau txhais plaub hom kev ua haujlwm uas tau tswj los ntawm chav kawm SpaceStation. Peb yuav khaws lawv hauv siab thaum refactoring. Cov lej hloov tshiab zoo dua qub nrog 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

Muaj ntau qhov kev hloov pauv, qhov program twv yuav raug hu zoo dua tam sim no. Tam sim no peb chav kawm SpaceStation tau dhau los ua ntau lub thawv uas tau pib ua haujlwm rau qhov chaw nyob, suav nrog cov txheej txheem sensors, cov khoom siv hluav taws xob, lub tank roj, thiab cov boosters.

Rau ib qho ntawm cov kev hloov pauv tam sim no muaj cov chav kawm sib xws: Sensors; SupplyHold; FuelTank; Thrusters.

Muaj ntau qhov kev hloov pauv tseem ceeb hauv qhov version ntawm tus lej no. Lub ntsiab lus yog tias ib tus neeg ua haujlwm tsis yog nyob hauv lawv tus kheej cov chav kawm xwb, lawv tau teeb tsa hauv txoj hauv kev los ua kom paub tseeb thiab sib xws. Peb pab pawg ua haujlwm nrog cov haujlwm zoo sib xws kom ua raws li lub hauv paus ntsiab lus ntawm kev sib koom ua ke. Tam sim no, yog tias peb yuav tsum hloov txoj hauv kev ua haujlwm, txav los ntawm cov qauv hash mus rau ib qho array, tsuas yog siv chav kawm SupplyHold; peb tsis tas yuav kov lwm cov qauv. Txoj kev no, yog tias tus tub ceev xwm logistics hloov qee yam hauv nws ntu, tus so ntawm lub chaw nres tsheb yuav nyob twj ywm. Hauv qhov no, chav kawm SpaceStation yuav tsis paub txog qhov hloov pauv.

Peb cov tub ceev xwm ua haujlwm ntawm qhov chaw nres tsheb yuav zoo siab txog qhov kev hloov pauv vim lawv tuaj yeem thov qhov lawv xav tau. Daim ntawv ceeb toom tias cov cai muaj txoj hauv kev xws li report_supplies thiab report_fuel muaj nyob rau hauv SupplyHold thiab FuelTank chav kawm. Yuav ua li cas yog lub ntiaj teb thov kom hloov txoj kev nws qhia? Ob chav kawm, SupplyHold thiab FuelTank, yuav tsum tau hloov. Yuav ua li cas yog tias koj yuav tsum tau hloov cov roj thiab consumables xa? Tej zaum koj yuav tau hloov tag nrho cov chav kawm qub dua. Thiab qhov no twb yog ib qho txhaum cai ntawm SRP. Cia peb kho qhov no.

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.

Hauv qhov kev hloov tshiab kawg no, lub luag haujlwm tau muab faib ua ob chav kawm tshiab, FuelReporter thiab SupplyReporter. Nkawd yog ob tug me nyuam ntawm chav Reporter. Tsis tas li ntawd, peb ntxiv cov piv txwv piv txwv rau SpaceStation chav kawm kom cov subclass xav tau tuaj yeem pib yog tias tsim nyog. Tam sim no, yog lub ntiaj teb txiav txim siab hloov lwm yam, ces peb yuav hloov pauv rau cov subclasses, thiab tsis yog rau cov chav kawm loj.

Tau kawg, qee qhov ntawm peb cov chav kawm tseem nyob ntawm ib leeg. Yog li, SupplyReporter khoom nyob ntawm SupplyHold, thiab FuelReporter nyob ntawm FuelTank. Tau kawg, cov boosters yuav tsum tau txuas nrog lub tank roj. Tab sis ntawm no txhua yam twb zoo li muaj laj thawj, thiab kev hloov pauv yuav tsis nyuaj tshwj xeeb - kho cov cai ntawm ib yam khoom yuav tsis cuam tshuam rau lwm tus.

Yog li, peb tau tsim ib qho kev cai modular uas lub luag haujlwm ntawm txhua yam ntawm cov khoom / chav kawm raug txhais tau meej. Ua haujlwm nrog cov cai zoo li no tsis yog teeb meem, kev tswj hwm nws yuav yog ib txoj haujlwm yooj yim. Peb tau hloov tag nrho "qhov khoom los saum ntuj los" rau hauv SRP.

Skillbox pom zoo:

Tau qhov twg los: www.hab.com

Ntxiv ib saib