د SOLID په کارولو سره د انعطاف وړ کوډ لیکل

د SOLID په کارولو سره د انعطاف وړ کوډ لیکل

له ژباړن څخه: ستاسو لپاره خپور شوی د سیورین پیریز لخوا مقاله په برنامه کې د SOLID اصولو کارولو په اړه. د مقالې معلومات به د پیل کونکو او تجربه لرونکو پروګرام کونکو لپاره ګټور وي.

که تاسو پرمختګ ته یاست، تاسو ډیری احتمال د SOLID اصولو په اړه اوریدلي یاست. دوی پروګرامر ته وړتیا ورکوي چې پاک، ښه جوړ شوی او په اسانۍ سره د ساتلو وړ کوډ ولیکي. دا د یادونې وړ ده چې په برنامه کولو کې د یوې ځانګړې دندې په سمه توګه ترسره کولو څرنګوالي لپاره ډیری لارې شتون لري. مختلف متخصصین د "سمه لار" په اړه مختلف نظرونه او پوهه لري؛ دا ټول د هر شخص په تجربه پورې اړه لري. په هرصورت، په SOLID کې اعلان شوي نظرونه د IT ټولنې نږدې ټولو استازو لخوا منل شوي. دوی د ډیری ښه پرمختیایي مدیریت طرزالعملونو رامینځته کولو او پراختیا لپاره د پیل ټکی و.

راځئ چې پوه شو چې د سولیډ اصول څه دي او دوی څنګه زموږ سره مرسته کوي.

Skillbox وړاندیز کوي: عملي کورس "د ګرځنده پرمخ وړونکي PRO".

موږ یادونه کوو: د ټولو هابر لوستونکو لپاره - د 10 روبل تخفیف کله چې د هابر پرومو کوډ په کارولو سره د مهارت بکس کوم کورس کې نوم لیکنه وکړئ.

SOLID څه شی دی؟

دا اصطالح یو لنډیز دی، د اصطالح هر لیک د یو ځانګړي اصول د نوم پیل دی:

  • Sد مسؤلیت اصل یو ماډل کولی شي د بدلون لپاره یو او یوازې یو دلیل ولري.
  • د Oقلم / تړل شوی اصول (د پرانیستې / تړلو اصولو). ټولګي او نور عناصر باید د تمدید لپاره خلاص وي، مګر د تعدیل لپاره تړل شوي.
  •  د Lد اسکوف د بدیل اصول (د لیسکوف د بدیل اصول). هغه دندې چې د بیس ډول کاروي باید د دې وړتیا ولري چې د بیس ډول فرعي ډولونه وکاروي پرته لدې چې پوه شي.
  • د Iد انٹرفیس جلا کولو اصول  (د انٹرفیس جلا کولو اصول). د سافټویر ادارې باید په میتودونو پورې اړه ونلري چې دوی یې نه کاروي.
  • د Dد انحصاري انعطاف اصول (د انحصار د انعطاف اصول). په لوړو کچو کې ماډلونه باید په ټیټو کچو ماډلونو پورې اړه ونلري.

د واحد مسؤلیت اصول


د واحد مسؤلیت اصول (SRP) وايي چې په برنامه کې هر ټولګي یا ماډل باید د دې برنامې فعالیت یوازې یوې برخې لپاره مسؤل وي. برسیره پردې، د دې مسؤلیت عناصر باید د دوی خپل ټولګي ته وټاکل شي، نه دا چې په غیر اړونده ټولګیو کې ویشل شي. د SRP پراختیا کونکی او لوی انجیل لیکونکی، رابرټ ایس مارټین، حساب ورکونه د بدلون لامل بولي. هغه په ​​اصل کې دا اصطلاح د هغه د کار د یو عنصر په توګه وړاندیز کړه "د اعتراض پر بنسټ ډیزاین اصول". مفهوم د ارتباط ډیری نمونې شاملوي چې مخکې د ټام ډیمارکو لخوا تعریف شوي.

په دې مفهوم کې د ډیویډ پارناس لخوا جوړ شوي ډیری مفکورې هم شاملې وې. دوه اصلي یې انکاپسول او د معلوماتو پټول دي. پارناس استدلال وکړ چې د سیسټم ویشل په جلا ماډلونو کې باید د بلاک ډیاګرامونو یا اجرایی جریانونو تحلیل پراساس نه وي. هر ماډل باید یو ځانګړی حل ولري چې پیرودونکو ته لږترلږه معلومات چمتو کوي.

په هرصورت، مارټین د شرکت لوړ پوړو مدیرانو (COO، CTO، CFO) سره په زړه پورې مثال ورکړ، چې هر یو یې د بیلابیلو موخو لپاره ځانګړي سوداګریز سافټویر کاروي. د پایلې په توګه، هر یو کولی شي په سافټویر کې بدلونونه پلي کړي پرته له دې چې د نورو مدیرانو ګټو اغیزه وکړي.

الهی څیز

د تل په څیر، د SRP زده کولو غوره لاره دا ده چې دا په عمل کې وګورئ. راځئ چې د پروګرام یوه برخه وګورو چې د واحد مسؤلیت اصول نه تعقیبوي. دا د روبي کوډ دی چې د فضا سټیشن چلند او ځانګړتیاوې بیانوي.

مثال ته بیا کتنه وکړئ او هڅه وکړئ چې لاندې مشخص کړئ:
د هغه شیانو مسؤلیتونه چې د سپیس سټیشن ټولګي کې اعلان شوي.
هغه څوک چې د فضا سټیشن عملیاتو سره علاقه لري.

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

په حقیقت کې، زموږ فضا سټیشن غیر فعال دی (زه فکر نه کوم چې زه به هر وخت ژر د ناسا څخه تلیفون ترلاسه کړم)، مګر دلته د تحلیل لپاره یو څه شتون لري.

په دې توګه، د سپیس سټیشن ټولګی ډیری مختلف مسؤلیتونه (یا دندې) لري. دوی ټول په ډولونو ویشل کیدی شي:

  • سینسرونه
  • توکي (د مصرف وړ توکي)؛
  • تېل
  • سرعت کونکي

که څه هم د سټیشن هیڅ کارمند ټولګی نه دی ګمارل شوی، موږ کولی شو په اسانۍ سره تصور وکړو چې څوک د څه لپاره مسؤل دي. ډیری احتمال، ساینس پوه سینسرونه کنټرولوي، لوژستیک د سرچینو رسولو مسولیت لري، انجنیر د تیلو اکمالاتو مسولیت لري، او پیلوټ بوسټر کنټرولوي.

ایا موږ کولی شو ووایو چې دا برنامه د SRP مطابق نه ده؟ هو، یقینا. مګر د SpaceStation ټولګی یو عام "خدای څیز" دی چې هرڅه پوهیږي او هرڅه کوي. دا د اعتراض پر بنسټ پروګرام کولو کې یو لوی ضد نمونه ده. د پیل کونکي لپاره، دا ډول توکي ساتل خورا ستونزمن دي. تر دې دمه برنامه خورا ساده ده ، هو ، مګر تصور وکړئ چې څه به پیښ شي که موږ نوي ځانګړتیاوې اضافه کړو. شاید زموږ فضا سټیشن به طبي سټیشن یا د ناستې خونې ته اړتیا ولري. او هرڅومره چې ډیر فعالیتونه شتون ولري ، د فضا سټیشن به وده وکړي. ښه، ځکه چې دا تاسیسات به له نورو سره وصل شي، د ټول کمپلیکس خدمت کول به نور هم پیچلي شي. د پایلې په توګه، موږ کولی شو عملیات ګډوډ کړو، د بیلګې په توګه، سرعت کونکي. که یو څیړونکی په سینسرونو کې د بدلون غوښتنه وکړي، دا کولی شي د سټیشن مخابراتي سیسټمونو باندې خورا ښه اغیزه وکړي.

د SRP د اصولو څخه سرغړونه کیدای شي لنډمهاله تاکتیکي بریا ورکړي، مګر په پای کې به موږ "جګړه له لاسه ورکړو"، او په راتلونکي کې به د داسې شیطان ساتل خورا ستونزمن وي. دا غوره ده چې برنامه د کوډ په جلا برخو وویشئ ، چې هر یو یې د ځانګړي عملیاتو ترسره کولو مسؤلیت لري. د دې په پوهیدو سره، راځئ چې د SpaceStation ټولګي بدل کړو.

راځئ چې مسؤلیتونه وویشو

پورته موږ څلور ډوله عملیات تعریف کړل چې د SpaceStation ټولګي لخوا کنټرول کیږي. موږ به دوی په ذهن کې وساتو کله چې د بیا کار کولو لپاره. تازه کوډ د 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

ډیر بدلونونه شتون لري، برنامه یقینا اوس ښه ښکاري. اوس زموږ د سپیس سټیشن ټولګی په یو کانټینر بدل شوی چې پکې د انحصاري برخو لپاره عملیات پیل شوي ، پشمول د سینسرونو سیټ ، د مصرف وړ اکمالاتو سیسټم ، د تیلو ټانک ، او بوسټر.

د هر متغیر لپاره اوس یو ورته طبقه شتون لري: سینسر؛ سپلائی هولډ د تیلو ټانکر؛ ټریسټرونه.

د کوډ په دې نسخه کې څو مهم بدلونونه شتون لري. ټکی دا دی چې انفرادي دندې نه یوازې په خپلو ټولګیو کې پوښل شوي، دوی په داسې ډول تنظیم شوي چې د وړاندوینې وړ او ثابت شي. موږ عناصر د ورته فعالیت سره ګروپ کوو ترڅو د همغږۍ اصول تعقیب کړو. اوس، که موږ اړتیا لرو چې د سیسټم کار کولو طریقه بدله کړو، د هش جوړښت څخه یو صف ته حرکت وکړو، یوازې د SupplyHold ټولګي وکاروئ؛ موږ اړتیا نلرو چې نورو ماډلونو ته لاس ورکړو. په دې توګه، که د لوژستیک افسر په خپله برخه کې یو څه بدل کړي، پاتې سټیشن به پاتې وي. په دې حالت کې، د سپیس سټیشن ټولګی به حتی د بدلونونو څخه خبر نه وي.

زموږ افسران چې په فضا سټیشن کې کار کوي شاید د بدلونونو څخه خوښ وي ځکه چې دوی کولی شي د هغه څه غوښتنه وکړي چې دوی ورته اړتیا لري. په یاد ولرئ چې کوډ میتودونه لري لکه د راپور_سپلیز او راپور_تیل په سپلائی هولډ او فیول ټانک ټولګیو کې شامل دي. څه به پیښ شي که چیرې ځمکه د راپور ورکولو طریقه بدله کړي؟ دواړه ټولګي، SupplyHold او FuelTank، باید بدل شي. که تاسو اړتیا لرئ د تیلو او مصرفي توکو رسولو لاره بدله کړئ؟ تاسو به شاید بیا ټول ورته ټولګي بدل کړئ. او دا لا دمخه د SRP اصولو څخه سرغړونه ده. راځئ چې دا سم کړو.

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.

د پروګرام په دې وروستي نسخه کې، مسؤلیتونه په دوو نویو ټولګیو ویشل شوي، د FuelReporter او SupplyReporter. دوی دواړه د خبریال ټولګي ماشومان دي. سربیره پردې ، موږ د سپیس سټیشن ټولګي کې د مثال متغیرونه اضافه کړل ترڅو مطلوب فرعي کلاس د اړتیا په صورت کې پیل شي. اوس، که ځمکه پریکړه وکړي چې بل څه بدل کړي، نو موږ به په فرعي ټولګیو کې بدلون راوړو، نه په اصلي طبقو کې.

البته، زموږ ځینې ټولګي لاهم په یو بل تکیه کوي. په دې توګه، د SupplyReporter اعتراض په SupplyHold پورې اړه لري، او FuelReporter په FuelTank پورې اړه لري. البته، بوسټر باید د تیلو ټانک سره وصل شي. مګر دلته هرڅه دمخه منطقي ښکاري ، او بدلونونه به په ځانګړي ډول ستونزمن نه وي - د یو څیز کوډ ترمیم کول به په بل ډیر اغیزه ونلري.

پدې توګه ، موږ یو ماډلر کوډ رامینځته کړی چیرې چې د هر شی / ټولګیو مسؤلیتونه په دقیق ډول تعریف شوي. د داسې کوډ سره کار کول کومه ستونزه نده، ساتل به یو ساده کار وي. موږ ټول "الهی څیز" په SRP کې بدل کړی دی.

Skillbox وړاندیز کوي:

سرچینه: www.habr.com

Add a comment