Cód solúbtha a scríobh ag baint úsáide as SOLID

Cód solúbtha a scríobh ag baint úsáide as SOLID

Ón aistritheoir: foilsithe ar do shon alt le Severin Perez faoi ​​úsáid a bhaint as prionsabail SOLID i gclárú. Beidh an fhaisnéis ón alt úsáideach do thosaitheoirí agus do ríomhchláraitheoirí a bhfuil taithí acu.

Má tá tú i mbun forbartha, is dócha gur chuala tú faoi na prionsabail SOLID. Cuireann siad ar chumas an ríomhchláraitheora cód glan, dea-struchtúrtha agus inchothaithe go héasca a scríobh. Is fiú a thabhairt faoi deara go bhfuil roinnt cur chuige i gcláir maidir le conas post áirithe a dhéanamh i gceart. Tá smaointe agus tuiscint éagsúil ag speisialtóirí éagsúla ar an “cosán ceart”; braitheann sé ar fad ar thaithí gach duine. Mar sin féin, glacann beagnach gach ionadaí den phobal TF leis na smaointe a fógraíodh i SOLID. Bhí siad mar phointe tosaigh maidir le teacht chun cinn agus forbairt go leor dea-chleachtas bainistíochta forbartha.

Tuigfimid cad iad na prionsabail SOLID agus conas a chuidíonn siad linn.

Molann Skillbox: Cúrsa praiticiúil "Forbróir Soghluaiste OCP".

Meabhraímid: do léitheoirí uile "Habr" - lascaine de 10 rúbal nuair a chláraíonn siad in aon chúrsa Scilbox ag baint úsáide as an gcód bolscaireachta "Habr".

Cad é SOLID?

Is giorrúchán é an téarma seo, is é gach litir den téarma tús an ainm prionsabal sonrach:

  • Single Prionsabal Freagrachta. Is féidir le modúl ach cúis amháin a bheith aige le hathrú.
  • An Opeann/Prionsabal Dúnta (prionsabal oscailte/dúnta). Ba cheart go mbeadh na haicmí agus na heilimintí eile oscailte le síneadh, ach dúnta le haghaidh modhnú.
  •  An LPrionsabal Ionadaíochta iskov (prionsabal ionadaíochta Liskov). Ba cheart go mbeadh feidhmeanna a úsáideann cineál bonn in ann fochineálacha den chineál bonn a úsáid i ngan fhios dó.
  • An IPrionsabal Deighilte Comhéadain  (prionsabal scaradh comhéadan). Níor cheart go mbeadh eintitis bogearraí ag brath ar mhodhanna nach n-úsáideann siad.
  • An Dpendency Inversion Prionsabal (prionsabal an inbhéartaithe spleáchais). Níor cheart go mbeadh modúil ag leibhéil níos airde ag brath ar mhodúil ag leibhéil níos ísle.

Prionsabal Freagrachta Aonair


Sonraítear sa Phrionsabal Freagrachta Aonair (SRP) gur cheart go mbeadh gach rang nó modúl i gclár freagrach as cuid amháin d’fheidhmiúlacht an chláir sin. Ina theannta sin, ba chóir gnéithe den fhreagracht seo a shannadh dá rang féin, seachas a bheith scaipthe ar fud ranganna neamhghaolmhara. Déanann forbróir SRP agus príomh-soiscéalaí, Robert S. Martin, cur síos ar chuntasacht mar chúis an athraithe. Mhol sé an téarma seo ar dtús mar cheann de na heilimintí dá chuid oibre "Prionsabail an Dearaidh atá Dírithe ar Oibiachtaí". Ionchorpraíonn an coincheap go leor den phatrún nascachta a shainigh Tom DeMarco roimhe seo.

Áiríodh leis an gcoincheap freisin roinnt coincheapa a chuir David Parnas le chéile. Is iad an dá phríomhchinn ná imchochlú agus faisnéis a cheilt. D’áitigh Parnas nár cheart córas a roinnt ina mhodúil ar leith a bheith bunaithe ar anailís ar bhlocléaráidí nó ar shreafaí forghníomhaithe. Ní mór go mbeadh réiteach sonrach in aon cheann de na modúil a sholáthraíonn íosmhéid faisnéise do chliaint.

Dála an scéil, thug Martin sampla suimiúil le bainisteoirí sinsearacha cuideachta (COO, CTO, CFO), agus úsáideann gach duine acu bogearraí gnó ar leith chun críocha éagsúla. Mar thoradh air sin, is féidir le haon cheann acu athruithe ar na bogearraí a chur i bhfeidhm gan cur isteach ar leasanna bainisteoirí eile.

réad Dhiaga

Mar is gnáth, is é an bealach is fearr chun SRP a fhoghlaim ná é a fheiceáil i ngníomh. Breathnaímid ar chuid den chlár NACH leanann an Prionsabal Freagrachta Aonair. Is é seo an cód Ruby a chuireann síos ar iompar agus tréithe an stáisiúin spáis.

Déan athbhreithniú ar an sampla agus déan iarracht na rudaí seo a leanas a chinneadh:
Freagrachtaí na n-oibiachtaí sin a dhearbhaítear san aicme SpaceStation.
Iad siúd a bhféadfadh suim a bheith acu in oibriú an stáisiúin spáis.

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

I ndáiríre, tá ár stáisiún spáis mífheidhmiúil (ní dóigh liom go mbeidh mé ag fáil glao ó NASA am ar bith go luath), ach tá rud éigin le anailísiú anseo.

Mar sin, tá go leor freagrachtaí (nó tascanna) éagsúla ar an rang SpaceStation. Is féidir iad go léir a roinnt i gcineálacha:

  • braiteoirí;
  • soláthairtí (earraí inchaite);
  • breosla ;
  • luasairí.

Cé nach sanntar rang d’aon duine d’fhostaithe an stáisiúin, is furasta dúinn a shamhlú cé atá freagrach as cad é. Is dócha go rialaíonn an t-eolaí na braiteoirí, tá an loighisticeoir freagrach as acmhainní a sholáthar, tá an t-innealtóir freagrach as soláthairtí breosla, agus rialaíonn an píolótach na teanndáileog.

An féidir linn a rá nach bhfuil an clár seo comhlíontach SRP? Sea, cinnte. Ach is "réad dia" tipiciúil é an rang SpaceStation a bhfuil a fhios aige gach rud agus a dhéanann gach rud. Is frith-patrún mór é seo i ríomhchlárú atá dírithe ar oibiachtaí. Do thosaitheoirí, tá rudaí den sórt sin thar a bheith deacair a choimeád ar bun. Go dtí seo tá an clár an-simplí, tá, ach samhlaigh cad a tharlóidh má chuirimid gnéithe nua leis. B'fhéidir go mbeidh stáisiún leighis nó seomra cruinnithe ag teastáil ónár stáisiún spáis. Agus dá mhéad feidhmeanna atá ann, is mó a fhásfaidh SpaceStation. Bhuel, ós rud é go mbeidh an áis seo ceangailte le daoine eile, beidh sé níos deacra fós an coimpléasc iomlán a sheirbhísiú. Mar thoradh air sin, is féidir linn cur isteach ar oibriú, mar shampla, luasairí. Má iarrann taighdeoir athruithe ar na braiteoirí, d'fhéadfadh sé seo cur isteach go mór ar chórais chumarsáide an stáisiúin.

Má sháraítear prionsabal an SRP b’fhéidir go dtabharfar bua oirbheartaíochta gearrthéarmach, ach sa deireadh “caillfimid an cogadh”, agus éireoidh sé an-deacair ollphéist den sórt sin a choinneáil sa todhchaí. Is fearr an clár a roinnt ina ranna ar leith den chód, agus tá gach ceann acu freagrach as oibríocht shonrach a dhéanamh. Agus é seo á thuiscint, déanaimis an rang SpaceStation a athrú.

Déanaimis freagracht a dháileadh

Thuas shainmhíomar ceithre chineál oibríochta atá á rialú ag an rang SpaceStation. Coinneoimid iad agus muid ag athmhacrú. Meaitseálann an cód nuashonraithe an SRP níos fearr.

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

Tá go leor athruithe, is cinnte go bhfuil cuma níos fearr ar an gclár anois. Anois tá ár rang SpaceStation tar éis éirí níos coimeádán ina gcuirtear tús le hoibríochtaí le haghaidh páirteanna cleithiúnacha, lena n-áirítear sraith braiteoirí, córas soláthair inchaite, umar breosla, agus teanndáileog.

I gcás aon cheann de na hathróga tá aicme comhfhreagrach ann anois: Braiteoirí; SupplyHold; Tanca Breosla; Trucailí.

Tá roinnt athruithe tábhachtacha sa leagan seo den chód. Is é an pointe nach bhfuil feidhmeanna aonair cuimsithe ach amháin ina gcuid ranganna féin, go bhfuil siad eagraithe ar bhealach a bheith intuartha agus comhsheasmhach. Déanaimid eilimintí a ghrúpáil le feidhmiúlacht chomhchosúil chun prionsabal na comhleanúnachais a leanúint. Anois, más gá dúinn an bealach a oibríonn an córas a athrú, ag bogadh ó struchtúr hash go eagar, bain úsáid as an rang SupplyHold; ní gá dúinn teagmháil a dhéanamh le modúil eile. Ar an mbealach seo, má athraíonn an t-oifigeach lóistíochta rud éigin ina chuid, fanfaidh an chuid eile den stáisiún slán. Sa chás seo, ní bheidh an rang SpaceStation fiú ar an eolas faoi na hathruithe.

Is dócha go bhfuil ár n-oifigigh atá ag obair ar an stáisiún spáis sásta leis na hathruithe mar is féidir leo na cinn a theastaíonn uathu a iarraidh. Tabhair faoi deara go bhfuil modhanna cosúil le report_supplies agus report_fuel sa chód atá sna ranganna SupplyHold agus FuelTank. Cad a tharlódh dá n-iarrfadh an Domhan an bealach a dtuairiscíonn sé a athrú? Beidh gá leis an dá rang, SupplyHold agus FuelTank, a athrú. Cad a tharlóidh má theastaíonn uait an bealach a sheachadtar breosla agus earraí inchaite a athrú? Is dócha go mbeidh ort na ranganna céanna go léir a athrú arís. Agus tá sé seo cheana féin sárú ar an bprionsabal SRP. A ligean ar a shocrú seo.

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.

Sa leagan is déanaí seo den chlár, tá na freagrachtaí roinnte ina dhá rang nua, FuelReporter agus SupplyReporter. Is páistí den rang Tuairisceoir iad beirt. Ina theannta sin, chuireamar athróga mar shampla leis an rang SpaceStation ionas gur féidir an fo-aicme atá ag teastáil a thúsú más gá. Anois, má chinneann an Domhan rud éigin eile a athrú, ansin déanfaimid athruithe ar na fo-aicmí, agus ní ar an bpríomhaicme.

Ar ndóigh, tá cuid dár ranganna fós ag brath ar a chéile. Mar sin, braitheann an réad SupplyReporter ar SupplyHold, agus braitheann FuelReporter ar FuelTank. Ar ndóigh, ní mór na teanndáileog a bheith ceangailte leis an umar breosla. Ach anseo tá cuma loighciúil ar gach rud cheana féin, agus ní bheidh sé thar a bheith deacair athruithe a dhéanamh - ní dhéanfaidh eagarthóireacht ar chód réad amháin difear mór do dhuine eile.

Mar sin, tá cód modúlach cruthaithe againn ina bhfuil na freagrachtaí a bhaineann le gach ceann de na cuspóirí/ranganna sainithe go beacht. Ní fadhb í oibriú le cód den sórt sin, is tasc simplí é a chothabháil. Táimid tar éis an “réad diaga” iomlán a thiontú ina SRP.

Molann Skillbox:

Foinse: will.com

Add a comment