Аз тарҷумон: барои шумо нашр шудааст мақолаи Северин Перес дар бораи истифодаи принципхои SOLID дар барномасозй. Маълумот аз мақола ҳам барои шурӯъкунандагон ва ҳам барои барномасозони ботаҷриба муфид хоҳад буд.
Агар шумо ба рушд машғул бошед, эҳтимол шумо дар бораи принсипҳои SOLID шунидаед. Онҳо ба барномасоз имкон медиҳанд, ки рамзи тоза, сохторбандишуда ва ба осонӣ нигоҳ дошташаванда нависад. Қобили зикр аст, ки дар барномасозӣ якчанд равишҳо барои дуруст иҷро кардани кори муайян мавҷуданд. Мутахассисони гуногун дар бораи «роҳи дуруст» ақида ва фаҳмиши гуногун доранд, ҳамааш ба таҷрибаи ҳар як шахс вобаста аст. Бо вуҷуди ин, ғояҳои дар SOLID эълоншуда аз ҷониби қариб ҳамаи намояндагони ҷомеаи IT қабул карда мешаванд. Онҳо нуқтаи ибтидоии пайдоиш ва рушди бисёр таҷрибаҳои хуби идоракунии рушд гардиданд.
Принсипи Ягона Масъулият (SRP) мегӯяд, ки ҳар як синф ё модули барнома бояд танҳо барои як қисми функсияи ин барнома масъул бошад. Илова бар ин, унсурҳои ин масъулият бояд ба синфи худ таъин карда шаванд, на дар синфҳои ба ҳам алоқаманд. Таҳиягар ва сарвари башоратгари SRP Роберт С. Мартин масъулиятро сабаби тағирот тавсиф мекунад. Ӯ дар ибтидо ин истилоҳро ҳамчун яке аз ҷузъҳои асари худ "Принсипҳои тарҳрезии ба объект нигаронидашуда" пешниҳод кардааст. Консепсия қисми зиёди намунаи пайвастшавиро дар бар мегирад, ки қаблан Том ДеМарко муайян карда буд.
Консепсия инчунин якчанд мафҳумҳоеро дар бар мегирад, ки аз ҷониби Дэвид Парнас таҳия шудааст. Ду чизи асосӣ инкапсуляция ва пинҳон кардани иттилоот мебошанд. Парнас изҳор дошт, ки тақсим кардани система ба модулҳои алоҳида набояд ба таҳлили диаграммаҳои блок ё ҷараёнҳои иҷро асос ёбад. Ҳар яке аз модулҳо бояд ҳалли мушаххасеро дар бар гиранд, ки ҳадди аққал маълумотро ба муштариён таъмин кунад.
Дар омади гап, Мартин бо менеҷерони аршади ширкат (COO, CTO, CFO), ки ҳар кадоми онҳо нармафзори мушаххаси тиҷорӣ барои мақсадҳои гуногун истифода мебаранд, як мисоли ҷолиб овард. Дар натиҷа, ҳар кадоми онҳо метавонанд бидуни таъсир ба манфиатҳои дигар менеҷерҳо дар нармафзор тағйирот ворид кунанд.
Объекти илоҳӣ
Чун ҳамеша, роҳи беҳтарини омӯхтани SRP ин дидани он дар амал аст. Биёед як фасли барномаро бубинем, ки Принсипи ягонаи масъулиятро риоя намекунад. Ин рамзи Ruby аст, ки рафтор ва атрибутҳои истгоҳи кайҳонро тавсиф мекунад.
Намунаро аз назар гузаронед ва кӯшиш кунед, ки чизҳои зеринро муайян кунед:
Масъулияти он объектҳое, ки дар синфи SpaceStation эълон шудаанд.
Онхое, ки ба кори станциям кайхонй марок зохир карда метавонанд.
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
Воқеан, истгоҳи кайҳонии мо корношоям аст (ман фикр намекунам, ки ба зудӣ ба ман аз NASA занг занам), аммо дар ин ҷо чизе барои таҳлил вуҷуд дорад.
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
Тағйироти зиёде мавҷуданд, барнома бешубҳа ҳоло беҳтар ба назар мерасад. Ҳоло синфи SpaceStation мо бештар ба як контейнер табдил ёфтааст, ки дар он амалиёт барои қисмҳои вобаста, аз ҷумла маҷмӯи сенсорҳо, системаи таъминоти истеъмолӣ, зарфи сӯзишворӣ ва тақвиятдиҳандаҳо оғоз мешавад.
Барои ҳар як тағирёбанда ҳоло синфи мувофиқ вуҷуд дорад: Сенсорҳо; SupplyHold; FuelTank; Мошинҳо.
Дар ин версияи код якчанд тағйироти муҳим вуҷуд дорад. Гап дар сари он аст, ки функсияҳои инфиродӣ на танҳо дар синфҳои худ фаро гирифта шудаанд, онҳо тавре ташкил карда шудаанд, ки пешгӯишаванда ва пайгирона шаванд. Мо унсурҳои дорои функсияҳои шабеҳро гурӯҳбандӣ мекунем, то принсипи ҳамоҳангиро риоя кунем. Ҳоло, агар ба мо лозим ояд, ки тарзи кори системаро тағир дода, аз сохтори хэш ба массив гузаред, танҳо синфи SupplyHold -ро истифода баред; мо набояд ба модулҳои дигар даст занем. Ҳамин тавр, агар корманди таъминоти моддӣ дар қисмати худ чизеро тағир диҳад, қисми боқимондаи станция бетағйир мемонад. Дар ин ҳолат, синфи SpaceStation ҳатто аз тағирот огоҳ нахоҳад шуд.
Афсарони мо, ки дар истгоҳи кайҳонӣ кор мекунанд, эҳтимол аз тағирот хушҳоланд, зеро онҳо метавонанд чизҳои заруриро дархост кунанд. Аҳамият диҳед, ки код дорои усулҳое ба монанди report_supplies ва report_fuel, ки дар синфҳои SupplyHold ва FuelTank мавҷуд аст. Агар Замин талаб кунад, ки тарзи гузориши худро тағир диҳад, чӣ мешавад? Ҳарду синф, SupplyHold ва FuelTank, бояд тағир дода шаванд. Чӣ бояд кард, агар ба шумо тарзи интиқоли сӯзишворӣ ва масолеҳи масрафиро тағир диҳед? Эҳтимол шумо бояд ҳамаи ҳамон синфҳоро дубора иваз кунед. Ва ин аллакай вайрон кардани принципи СРП мебошад. Биёед инро ислоҳ кунем.
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.