Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

หลักการออกแบบที่มั่นคงใน Ruby

แอปพลิเคชันซอฟต์แวร์ทั้งหมดเปลี่ยนแปลงตลอดเวลา การเปลี่ยนแปลงที่ทำกับซอฟต์แวร์อาจทำให้เกิดปัญหาการเรียงซ้อนที่ไม่คาดคิด อย่างไรก็ตาม การเปลี่ยนแปลงเป็นสิ่งที่หลีกเลี่ยงไม่ได้ เนื่องจากเราไม่สามารถสร้างซอฟต์แวร์ที่ไม่เปลี่ยนแปลงได้ ข้อกำหนดของซอฟต์แวร์ยังคงเปลี่ยนแปลงต่อไปเมื่อซอฟต์แวร์เติบโตขึ้น สิ่งที่เราทำได้คือออกแบบซอฟต์แวร์ให้มีความยืดหยุ่นในการเปลี่ยนแปลง การออกแบบซอฟต์แวร์อย่างถูกต้องอาจต้องใช้เวลาและความพยายามตั้งแต่เริ่มต้น แต่ในระยะยาวจะช่วยประหยัดเวลาและความพยายาม ซอฟต์แวร์ที่เชื่อมต่อกันอย่างแน่นหนานั้นเปราะบาง และเราไม่สามารถคาดการณ์ว่าจะเกิดอะไรขึ้นกับการเปลี่ยนแปลง นี่คือผลกระทบบางส่วนจากซอฟต์แวร์ที่ออกแบบมาไม่ดี:

  • มันทำให้เคลื่อนที่ไม่ได้
  • การเปลี่ยนรหัสมีราคาแพง
  • การเพิ่มความซับซ้อนง่ายกว่าการทำให้ซอฟต์แวร์ง่ายขึ้น
  • รหัสนี้ไม่สามารถจัดการได้
  • นักพัฒนาซอฟต์แวร์ต้องใช้เวลามากในการค้นหาวิธีการทำงานของฟังก์ชัน
  • การเปลี่ยนซอฟต์แวร์ส่วนหนึ่งมักจะทำให้อีกส่วนหนึ่งเสียหาย และเราไม่สามารถคาดการณ์ได้ว่าการเปลี่ยนแปลงจะนำไปสู่ปัญหาใด

หลักการออกแบบกระดาษและรูปแบบการออกแบบ ระบุอาการต่อไปนี้ของซอฟต์แวร์ที่เน่าเปื่อย:

  • ความเข้มงวด:การเปลี่ยนรหัสโดยไม่ทำให้เกิดปัญหาเป็นเรื่องยากมาก เนื่องจากการเปลี่ยนแปลงในส่วนใดส่วนหนึ่งจะทำให้จำเป็นต้องเปลี่ยนแปลงในส่วนอื่นๆ ของโค้ด
  • ความเปราะบาง:การเปลี่ยนรหัสมักจะทำให้การทำงานของซอฟต์แวร์หยุดชะงัก แม้กระทั่งชิ้นส่วนที่ไม่เกี่ยวข้องโดยตรงกับการเปลี่ยนแปลงก็ได้
  • ความไม่สามารถเคลื่อนที่ได้:แม้ว่าบางส่วนของแอปพลิเคชันซอฟต์แวร์อาจมีพฤติกรรมคล้ายกัน แต่เราไม่สามารถใช้โค้ดซ้ำได้และต้องทำซ้ำโค้ดเหล่านั้น
  • ความหนืด:เมื่อซอฟต์แวร์เปลี่ยนแปลงได้ยาก เราจะเพิ่มความซับซ้อนให้กับซอฟต์แวร์แทนที่จะทำให้ดีขึ้น

จำเป็นต้องออกแบบซอฟต์แวร์ในลักษณะที่สามารถควบคุมและคาดการณ์การเปลี่ยนแปลงได้

หลักการออกแบบ SOLID ช่วยแก้ไขปัญหาเหล่านี้โดยแยกโปรแกรมซอฟต์แวร์ออก Robert C. Martin แนะนำแนวคิดเหล่านี้ในบทความเรื่อง Design Principles and Design Patterns และ Michael Feathers ได้ใช้ตัวย่อในภายหลัง

หลักการออกแบบ SOLID ประกอบด้วยหลักการ 5 ข้อต่อไปนี้:

  • หลักการความรับผิดชอบของ ingle
  • โอ ปากกา/หลักการปิด
  • หลักการทดแทน iskov
  • ฉัน หลักการแยกส่วนหน้า
  • หลักการผกผัน ependency

เราจะสำรวจแต่ละข้อเพื่อทำความเข้าใจว่าหลักการเหล่านี้จะช่วยสร้างซอฟต์แวร์ที่ออกแบบมาอย่างดีใน Ruby ได้อย่างไร

หลักการความรับผิดชอบเดียว - SRP

สมมติว่าสำหรับซอฟต์แวร์การจัดการ HR เราจำเป็นต้องมีฟังก์ชันการทำงานเพื่อสร้างผู้ใช้ เพิ่มเงินเดือนของพนักงาน และสร้างสลิปเงินเดือนของพนักงาน ขณะสร้าง เราสามารถเพิ่มฟังก์ชันเหล่านี้ในคลาสเดียวได้ แต่วิธีนี้ทำให้เกิดการพึ่งพาที่ไม่ต้องการระหว่างฟังก์ชันเหล่านี้ เป็นเรื่องง่ายเมื่อเราเริ่มต้น แต่เมื่อมีการเปลี่ยนแปลงและความต้องการใหม่เกิดขึ้น เราจะไม่สามารถคาดการณ์ได้ว่าการเปลี่ยนแปลงจะทำให้เกิดฟังก์ชันการทำงานใด

ชั้นเรียนควรมีหนึ่งเหตุผล และมีเพียงเหตุผลเดียวที่จะเปลี่ยน - Robert C Martin

นี่คือตัวอย่างโค้ดที่ฟังก์ชันทั้งหมดอยู่ในคลาสเดียว:

class User
  def initialize(employee, month)
    @employee = employee
    @month = month
  end

  def generate_payslip
    # Code to read from database,
    # generate payslip
    # and write it to a file
    self.send_email
  end

  def send_email
    # code to send email
    employee.email
    month
  end
end

ในการสร้างสลิปเงินเดือนและส่งให้กับผู้ใช้ เราสามารถเริ่มต้นคลาสและเรียกวิธีสร้างสลิปเงินเดือน:

  month = 11
  user = User.new(employee, month)
  user.generate_payslip

ตอนนี้มีข้อกำหนดใหม่ เราต้องการสร้างสลิปเงินเดือนแต่ไม่ต้องการส่งอีเมล เราจำเป็นต้องคงฟังก์ชันการทำงานที่มีอยู่เดิมไว้และเพิ่มเครื่องมือสร้างสลิปเงินเดือนใหม่สำหรับการรายงานภายในโดยไม่ต้องส่งอีเมล เนื่องจากเป็นข้อเสนอภายใน ในระหว่างขั้นตอนนี้ เราต้องการให้แน่ใจว่าสลิปเงินเดือนที่ส่งถึงพนักงานยังคงใช้งานได้

สำหรับข้อกำหนดนี้ เราไม่สามารถใช้รหัสที่มีอยู่ซ้ำได้ เราจำเป็นต้องเพิ่มการตั้งค่าสถานะในวิธี generate_payslip โดยบอกว่าหาก true ส่งอีเมลอย่างอื่นไม่ทำ สามารถทำได้ แต่เนื่องจากเปลี่ยนรหัสที่มีอยู่ อาจทำให้ฟังก์ชันการทำงานที่ออกไม่ได้

เพื่อให้แน่ใจว่าเราจะไม่ทำลายสิ่งต่าง ๆ เราต้องแยกตรรกะเหล่านี้ออกเป็นคลาสที่แยกจากกัน:

  class PayslipGenerator
    def initialize(employee, month)
      @employee = employee
      @month = month
    end

    def generate_payslip
      # Code to read from database,
      # generate payslip
      # and write it to a file
    end
  end
  class PayslipMailer
    def initialize(employee)
      @employee = employee
    end

    def send_mail
      # code to send email
      employee.email
      month
    end
  end

ต่อไป เราสามารถเริ่มต้นทั้งสองคลาสนี้และเรียกใช้เมธอดของพวกมัน:

  month = 11
  # General Payslip
  generator = PayslipGenerator.new(employee, month)
  generator.generate_payslip
  # Send Email
  mailer = PayslipMailer.new(employee, month)
  mailer.send_mail

แนวทางนี้ช่วยแยกความรับผิดชอบและรับรองการเปลี่ยนแปลงที่คาดการณ์ได้ หากเราจำเป็นต้องเปลี่ยนฟังก์ชันจดหมายเท่านั้น เราสามารถทำได้โดยไม่ต้องเปลี่ยนการสร้างรายงาน นอกจากนี้ยังช่วยในการคาดคะเนการเปลี่ยนแปลงในการทำงาน

สมมติว่าเราต้องเปลี่ยนรูปแบบของช่องเดือนในอีเมลเป็น Nov แทน 11 . ในกรณีนี้ เราจะปรับเปลี่ยนคลาส PayslipMailer และเพื่อให้แน่ใจว่าจะไม่มีอะไรเปลี่ยนแปลงหรือเสียหายในฟังก์ชัน PayslipGenerator

ทุกครั้งที่คุณเขียนโค้ด ให้ถามคำถามในภายหลัง ความรับผิดชอบของชั้นนี้คืออะไร? หากคำตอบของคุณมี "และ" อยู่ ให้แบ่งชั้นเรียนออกเป็นหลายชั้นเรียน คลาสที่เล็กกว่าย่อมดีกว่าคลาสใหญ่ทั่วไปเสมอ

หลักการเปิด/ปิด - OCP

Bertrand Meyer เป็นผู้ริเริ่มหลักการเปิด/ปิดในหนังสือของเขาที่ชื่อว่า Object-Oriented Software Construction

หลักการระบุว่า "เอนทิตีซอฟต์แวร์ (คลาส โมดูล ฟังก์ชัน ฯลฯ) ควรเปิดเพื่อขยาย แต่ปิดเพื่อแก้ไข " นี่หมายความว่าเราควรจะเปลี่ยนพฤติกรรมโดยไม่ต้องเปลี่ยนเอนทิตี

ในตัวอย่างข้างต้น เรามีฟังก์ชันการส่งสลิปเงินเดือนสำหรับพนักงาน แต่ฟังก์ชันดังกล่าวเป็นฟังก์ชันทั่วไปสำหรับพนักงานทุกคน อย่างไรก็ตาม มีข้อกำหนดใหม่เกิดขึ้น:สร้างสลิปเงินเดือนตามประเภทของพนักงาน เราต้องการตรรกะการสร้างบัญชีเงินเดือนที่แตกต่างกันสำหรับพนักงานประจำและผู้รับเหมา ในกรณีนี้ เราสามารถแก้ไข PayrollGenerator ที่มีอยู่และเพิ่มฟังก์ชันเหล่านี้:

class PayslipGenerator
  def initialize(employee, month)
    @employee = employee
    @month = month
  end

  def generate_payslip
    # Code to read from database,
    # generate payslip
    if employee.contractor?
        # generate payslip for contractor
    else
        # generate a normal payslip
    end
    # and write it to a file
  end
end

อย่างไรก็ตาม นี่เป็นการตบตีที่ไม่ดี ในการทำเช่นนั้น เรากำลังแก้ไขคลาสที่มีอยู่ หากเราต้องการเพิ่มตรรกะการสร้างเพิ่มเติมตามสัญญาของพนักงาน เราจำเป็นต้องแก้ไขคลาสที่มีอยู่ แต่การทำเช่นนั้นจะเป็นการละเมิดหลักการเปิด/ปิด การปรับเปลี่ยนคลาสทำให้เราเสี่ยงที่จะทำการเปลี่ยนแปลงโดยไม่ได้ตั้งใจ เมื่อมีการเปลี่ยนแปลงหรือเพิ่มบางอย่าง อาจทำให้เกิดปัญหาที่ไม่รู้จักในโค้ดที่มีอยู่ if-else เหล่านี้สามารถทำได้ในที่ต่างๆ ภายในคลาสเดียวกัน ดังนั้น เมื่อเราเพิ่มประเภทพนักงานใหม่ เราอาจพลาดสถานที่ที่มี if-else เหล่านี้อยู่ การค้นหาและแก้ไขทั้งหมดอาจมีความเสี่ยงและอาจสร้างปัญหาได้

เราสามารถจัดโครงสร้างโค้ดนี้ใหม่ในลักษณะที่เราสามารถเพิ่มฟังก์ชันการทำงานโดยขยายฟังก์ชันการทำงาน แต่หลีกเลี่ยงการเปลี่ยนเอนทิตี ดังนั้น ให้เราสร้างคลาสแยกกันสำหรับแต่ละรายการและมี generate . เหมือนกัน วิธีการแต่ละอย่าง:

class ContractorPayslipGenerator
  def initialize(employee, month)
    @employee = employee
    @month = month
  end

  def generate
    # Code to read from the database,
    # generate payslip
    # and write it to a file
  end
end
class FullTimePayslipGenerator
  def initialize(employee, month)
    @employee = employee
    @month = month
  end

  def generate
    # Code to read from the database,
    # generate payslip
    # and write it to a file
  end
end

ตรวจสอบให้แน่ใจว่าสิ่งเหล่านี้มีชื่อวิธีการเดียวกัน ตอนนี้ เปลี่ยนคลาส PayslipGenerator เพื่อใช้คลาสเหล่านี้:

GENERATORS = {
  'full_time' => FullTimePayslipGenerator,
  'contractor' => ContractorPayslipGenerator
}

class PayslipGenerator
  def initialize(employee, month)
    @employee = employee
    @month = month
  end

  def generate_payslip
    # Code to read from database,
    # generate payslip
    GENERATORS[employee.type].new(employee, month).generate()
    # and write it to a file
  end
end

ที่นี่ เรามีค่าคงที่ GENERATORS ที่แมปคลาสที่จะเรียกตามประเภทพนักงาน เราสามารถใช้เพื่อกำหนดคลาสที่จะเรียก ตอนนี้ เมื่อเราต้องเพิ่มฟังก์ชันการทำงานใหม่ เราสามารถสร้างคลาสใหม่สำหรับสิ่งนั้นและเพิ่มในค่าคงที่ GENERATORS สิ่งนี้ช่วยขยายชั้นเรียนโดยไม่ทำลายบางสิ่งหรือต้องคิดเกี่ยวกับตรรกะที่มีอยู่ เราสามารถเพิ่มหรือลบโปรแกรมสร้างสลิปเงินเดือนประเภทใดก็ได้

หลักการทดแทน Liskov - LSP

หลักการแทนที่ Liskov ระบุว่า "ถ้า S เป็นประเภทย่อยของ T วัตถุประเภท T อาจถูกแทนที่ด้วยวัตถุประเภท S" .

เพื่อให้เข้าใจหลักการนี้ ให้เราเข้าใจปัญหาก่อน ภายใต้หลักการเปิด/ปิด เราออกแบบซอฟต์แวร์ในลักษณะที่สามารถขยายได้ เราได้สร้างตัวสร้าง Payslip คลาสย่อยที่ทำงานเฉพาะ สำหรับผู้โทร คลาสที่พวกเขากำลังโทรไม่เป็นที่รู้จัก คลาสเหล่านี้ต้องมีพฤติกรรมเหมือนกันเพื่อให้ผู้โทรไม่สามารถบอกความแตกต่างได้ โดยพฤติกรรม เราหมายความว่าวิธีการในชั้นเรียนควรสอดคล้องกัน เมธอดในคลาสเหล่านี้ควรมีลักษณะดังต่อไปนี้:

  • มีชื่อเหมือนกัน
  • ใช้อาร์กิวเมนต์จำนวนเท่ากันกับประเภทข้อมูลเดียวกัน
  • คืนค่าประเภทข้อมูลเดิม

ให้เราดูตัวอย่างของเครื่องกำเนิดสลิปเงินเดือน เรามีเครื่องปั่นไฟสองเครื่อง เครื่องหนึ่งสำหรับพนักงานประจำและอีกเครื่องสำหรับผู้รับเหมา ตอนนี้ เพื่อให้แน่ใจว่าสลิปเงินเดือนเหล่านี้มีพฤติกรรมที่สอดคล้องกัน เราจำเป็นต้องสืบทอดจากคลาสพื้นฐาน ให้เรากำหนดคลาสพื้นฐานที่เรียกว่า User .

class User
  def generate
  end
end

คลาสย่อยที่เราสร้างขึ้นในตัวอย่างของหลักการเปิด/ปิดไม่มีคลาสพื้นฐาน เราแก้ไขให้มีคลาสฐาน User :

class ContractorPayslipGenerator < User
  def generate
    # Code to generate payslip
  end
end
class FullTimePayslipGenerator < User
  def generate
    # Code to generate payslip
  end
end

ต่อไป เรากำหนดชุดของเมธอดที่จำเป็นสำหรับคลาสย่อยใดๆ ที่สืบทอด User ระดับ. เรากำหนดวิธีการเหล่านี้ในคลาสพื้นฐาน ในกรณีของเรา เราต้องการวิธีเดียวเท่านั้นที่เรียกว่า สร้าง

class User
  def generate
    raise "NotImplemented"
  end
end

ที่นี่เราได้กำหนดวิธีการสร้างซึ่งมี raise คำแถลง. ดังนั้น คลาสย่อยใดๆ ที่สืบทอดคลาสพื้นฐานจำเป็นต้องมีเมธอด create หากไม่มีอยู่ จะทำให้เกิดข้อผิดพลาดว่าไม่ได้ใช้วิธีนี้ ด้วยวิธีนี้ เราจึงมั่นใจได้ว่าคลาสย่อยจะสอดคล้องกัน ด้วยเหตุนี้ ผู้โทรจึงมั่นใจได้ว่า generate วิธีการมีอยู่

หลักการนี้ช่วยแทนที่คลาสย่อยใดๆ ได้อย่างง่ายดายโดยไม่ทำให้สิ่งของเสียหายและไม่จำเป็นต้องทำการเปลี่ยนแปลงมากมาย

หลักการแยกส่วนต่อประสาน - ISP

หลักการแยกส่วนต่อประสานใช้ได้กับภาษาคงที่ และเนื่องจาก Ruby เป็นภาษาไดนามิก จึงไม่มีแนวคิดเกี่ยวกับอินเทอร์เฟซ อินเทอร์เฟซกำหนดกฎนามธรรมระหว่างคลาสต่างๆ

หลักการกล่าวไว้

ลูกค้าไม่ควรถูกบังคับให้พึ่งพาอินเทอร์เฟซที่พวกเขาไม่ได้ใช้ - โรเบิร์ต ซี. มาร์ติน

สิ่งนี้หมายความว่าจะดีกว่าที่จะมีอินเทอร์เฟซจำนวนมากกว่าอินเทอร์เฟซทั่วไปที่คลาสใด ๆ สามารถใช้ได้ หากเรากำหนดอินเทอร์เฟซทั่วไป คลาสจะต้องขึ้นอยู่กับคำจำกัดความที่ไม่ได้ใช้

Ruby ไม่มีอินเทอร์เฟซ แต่ให้เราดูที่แนวคิดคลาสและคลาสย่อยเพื่อสร้างสิ่งที่คล้ายกัน

ในตัวอย่างที่ใช้สำหรับหลักการทดแทน Liskov เราพบว่าคลาสย่อย FullTimePayslipGenerator ได้รับการสืบทอดมาจากผู้ใช้คลาสทั่วไป แต่ User เป็นคลาสทั่วไปและอาจมีวิธีอื่น หากเราต้องมีฟังก์ชันอื่น เช่น Leave มันจะต้องเป็นคลาสย่อยของ User Leave ไม่จำเป็นต้องมีวิธีการสร้าง แต่จะขึ้นอยู่กับวิธีนี้ ดังนั้น แทนที่จะมีคลาสทั่วไป เราสามารถมีคลาสเฉพาะสำหรับสิ่งนี้:

class Generator
  def generate
    raise "NotImplemented"
  end
end
class ContractorPayslipGenerator < Generator
  def generate
    # Code to generate payslip
  end
end
class FullTimePayslipGenerator < Generator
  def generate
    # Code to generate payslip
  end
end

ตัวสร้างนี้เฉพาะสำหรับการสร้างสลิปเงินเดือน และคลาสย่อยไม่จำเป็นต้องพึ่งพา User ทั่วไป ชั้นเรียน

หลักการผกผันการพึ่งพา - DIP

การผกผันการพึ่งพาเป็นหลักการที่ใช้เพื่อแยกโมดูลซอฟต์แวร์ออก

โมดูลระดับสูงไม่ควรขึ้นอยู่กับโมดูลระดับต่ำ ทั้งสองควรขึ้นอยู่กับนามธรรม

การออกแบบโดยใช้หลักการที่อธิบายข้างต้น จะนำเราไปสู่หลักการผกผันการพึ่งพา ชั้นเรียนใด ๆ ที่มีความรับผิดชอบเดียวต้องการสิ่งต่าง ๆ จากชั้นเรียนอื่นเพื่อทำงาน ในการสร้างบัญชีเงินเดือน เราจำเป็นต้องเข้าถึงฐานข้อมูล และเราจำเป็นต้องเขียนลงในไฟล์เมื่อสร้างรายงานแล้ว ด้วยหลักการความรับผิดชอบเดียว เรากำลังพยายามมีงานเพียงงานเดียวสำหรับชั้นเรียนเดียว แต่สิ่งต่างๆ เช่น การอ่านจากฐานข้อมูลและการเขียนไปยังไฟล์จำเป็นต้องดำเนินการภายในคลาสเดียวกัน

สิ่งสำคัญคือต้องลบการพึ่งพาเหล่านี้ออกและแยกตรรกะทางธุรกิจหลักออก ซึ่งจะช่วยให้โค้ดมีความลื่นไหลระหว่างการเปลี่ยนแปลง และการเปลี่ยนแปลงสามารถคาดเดาได้ การขึ้นต่อกันจำเป็นต้องกลับด้าน และผู้เรียกของโมดูลควรควบคุมการขึ้นต่อกัน ในตัวสร้างสลิปเงินเดือน การขึ้นต่อกันเป็นแหล่งข้อมูลสำหรับรายงาน รหัสนี้ควรจัดในลักษณะที่ผู้โทรสามารถระบุแหล่งที่มาได้ การควบคุมการพึ่งพาจะต้องถูกพลิกกลับและผู้โทรสามารถแก้ไขได้ง่าย

หลักการออกแบบที่มั่นคงใน Ruby

ในตัวอย่างด้านบนของเรา ContractorPayslipGenerator โมดูลควบคุมการพึ่งพา เนื่องจากการกำหนดตำแหน่งที่จะอ่านข้อมูลและวิธีการจัดเก็บผลลัพธ์นั้นถูกควบคุมโดยชั้นเรียน หากต้องการย้อนกลับ ให้เราสร้าง UserReader คลาสที่อ่านข้อมูลผู้ใช้:

class UserReader
  def get
    raise "NotImplemented"
  end
end

ตอนนี้ ให้เราสมมติว่าเราต้องการให้สิ่งนี้อ่านข้อมูลจาก Postgres เราสร้างคลาสย่อยของ UserReader เพื่อจุดประสงค์นี้:

class PostgresUserReader < UserReader
  def get
    # Code to read data from Postgres
  end
end

ในทำนองเดียวกัน เราสามารถมีโปรแกรมอ่านจาก FileUserReader , InMemoryUserReader หรือผู้อ่านประเภทอื่น ๆ ที่เราต้องการ ตอนนี้เราต้องแก้ไข FullTimePayslipGenerator คลาสเพื่อใช้ PostgresUserReader เป็นที่พึ่งได้

class FullTimePayslipGenerator < Generator
  def initialize(datasource)
    @datasource = datasource
  end

  def generate
    # Code to generate payslip
    data = datasource.get()
  end
end

ผู้โทรสามารถส่ง PostgresUserReader . ได้แล้ว เป็นการพึ่งพา:

datasource = PostgresUserReader.new()
FullTimePayslipGenerator.new(datasource)

ผู้โทรสามารถควบคุมการพึ่งพาและสามารถเปลี่ยนแหล่งที่มาได้อย่างง่ายดายเมื่อจำเป็น

การแปลงการพึ่งพาไม่ได้มีผลกับคลาสเท่านั้น เราต้องสลับการกำหนดค่าด้วย ตัวอย่างเช่น ขณะเชื่อมต่อเซิร์ฟเวอร์ Postgres เราจำเป็นต้องมีการกำหนดค่าเฉพาะ เช่น DBURL ชื่อผู้ใช้ และรหัสผ่าน แทนที่จะฮาร์ดโค้ดการกำหนดค่าเหล่านี้ในคลาส เราต้องส่งต่อจากผู้โทร

class PostgresUserReader < UserReader
  def initialize(config)
    config = config
  end

  def get
    # initialize DB with the config
    self.config
    # Code to read data from Postgres
  end
end

ระบุการกำหนดค่าโดยผู้โทร:

  config = { url: "url", user: "user" }
  datasource = PostgresUserReader.new(config)
  FullTimePayslipGenerator.new(datasource)

ขณะนี้ผู้โทรเข้าควบคุมการพึ่งพาได้อย่างสมบูรณ์ และการจัดการการเปลี่ยนแปลงทำได้ง่ายและเจ็บปวดน้อยลง

กำลังสรุป

การออกแบบ SOLID ช่วยในการแยกโค้ดและทำให้การเปลี่ยนแปลงเจ็บปวดน้อยลง สิ่งสำคัญคือต้องออกแบบโปรแกรมในลักษณะที่แยกส่วน ใช้ซ้ำได้ และตอบสนองต่อการเปลี่ยนแปลง หลักการ SOLID ทั้งหมดห้าข้อช่วยเสริมซึ่งกันและกันและควรอยู่ร่วมกัน โค้ดเบสที่ออกแบบมาอย่างดีนั้นยืดหยุ่น เปลี่ยนแปลงได้ง่าย และใช้งานได้สนุก นักพัฒนาใหม่ทุกคนสามารถเข้าร่วมและเข้าใจโค้ดได้อย่างง่ายดาย

สิ่งสำคัญคือต้องเข้าใจว่าปัญหาประเภทใดที่ SOLID แก้ไขได้ และเหตุใดเราจึงทำเช่นนี้ การเข้าใจปัญหาจะช่วยให้คุณยอมรับหลักการออกแบบและออกแบบซอฟต์แวร์ได้ดีขึ้น