DEV Community

FaxriddinMaxmadiyorov
FaxriddinMaxmadiyorov

Posted on • Edited on

SOLID Design Principles in Ruby

SOLID - dasturni yanada tushunarli, o'zgartirishga va kattalashtirishga imkon beruvchi principlar yig'indisi.

  • Single Responsibility Principle (SRP)
  • Open/Closed Principle (OCP)
  • Liskov Substitution Principle (LSP)
  • Interface Segregation Principle (ISP)
  • Dependency Inversion Principle (DIP)

1. Single Responsibility Principle
Har bir class faqatgina bitta funksionalga javob berishi kerak. Ko'p funksional'larni bitta class'da yozilgan bo'lsa, o'sha classni o'zgartirish hamma funksionallarni o'zgartirishga olib kelishi mumkin.

class Employee
  def process_data
  end

  def send_message(message)
  end
end
Enter fullscreen mode Exit fullscreen mode

masalan, bizda Employee class bor, unda process_data va send_message method'lari mavjud. send_message method'ga o'zgartirish kerak bo'lsa, Employee classni ichida o'zgartirishga to'g'ri keladi. Bundan tashqari, mijozlarga ham message yuborish kerak bo'lsa, Client class'ni ichida ham send_message methodini yozishimizga to'g'ri keladi.

class Employee
  def process_data; end
end

class Client
  def process_data; end
end

class Message
  def send_message(user, message)
  end
end

Enter fullscreen mode Exit fullscreen mode

Agar yuboriladigan message o'zgartirilishi kerak bo'lsa, Message classni ichida o'zgartirishimiz kifoya.

2. Open/Closed Principle (OCP)
Classlar kengaytirish uchun ochiq, lekin o'zgartirish yoki refaktor qilish uchun yopiq bo'lishi kerak. Bu printsip classni imkoniyatini oshirish uchun allaqachon ishlab turgan classni o'zgartirmaslikni eslatadi. Masalan bizda InvoiceReport class bor, u hozircha orderni pdf va csv formatlarda generate qiladi.

class InvoiceReport
  def initialize(order, type)
    @order = order
    @type = type
  end

  def generate
    case @type
    when 'pdf'
      # pdf generation
    when 'csv'
      # csv generation
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

Endi xls formatda ham report generate qilmoqchimiz, va InvoiceReport classga qo'shishimiz kerak. Buni oldini olish uchun Open/Closed Principle ishlatishimiz mumkin:

class InvoiceReport
  def initialize(order, klass)
    @order = order
    @klass = klass
  end

  def generate
    @klass.new(@order).generate
  end
end

class PdfGenerator
  def initialize(order)
    @order = order
  end

  def generate
    # Generate PDF report
    puts "PDF Report generated"
  end
end

class CsvGenerator
  def initialize(order)
    @order = order
  end

  def generate
    # Generate CSV report
    puts "CSV Report generated"
  end
end
Enter fullscreen mode Exit fullscreen mode

3. Liskov Substitution Principle
if S could be a sub-type of T, then objects of type T is also replaced with objects of type S - Agar S class T classni child classi bo'lsa, T classni obyektlari S classni obyektlari bilan muvofiq bo'lishi kerak.

class User
  attr_accessor :name

  def initialize(name)
    @name = name
  end

  def report
    raise 'Not implemented for User class'
  end
end

class Employee < User
  def initialize(name)
    super
  end

  def report
    puts "Report method called!!!"
  end
end
Enter fullscreen mode Exit fullscreen mode

Agar child class o’zining ota class’i bilan bir xil amallarni bajara olmasa, bu xatolarga olib kelishi mumkin.

Agar sizda class mavjud bo’lsa va undan yangi yangi class yaratsangiz, u parent (ota) va yangi class esa child (farzand) class bo’ladi. Child class ota class bajara olgan barcha narsani qila olishi kerak. Bu jarayon Inheritance deyiladi.

Child class bir xil so’rovlarni qayta ishlashi va parent class bilan bir xil yoki bir turdagi natijani berishi kerak.

Ushbu tamoyil asosiy sinf yoki uning pastki sinfi hech qanday xatosiz bir xil tarzda ishlatilishi uchun o’zgarmaslikni ta’minlashga qaratilgan.

4. Interface Segregation
Interface Segregation tamoyili client ishlatmaydigan methodga bog'liq bo'lmasligini aytadi. Boshqacha qilib aytganda, bitta umumiy katta interfeysdan ko'ra classni o'zigagina tegishli interfeyslar yaratish g'oyasini qo'llaydi.

module PrinterFunctions
  def print

  end

  def scan

  end

  def fax

  end
end

class Printer
  include PrinterFunctions
end
Enter fullscreen mode Exit fullscreen mode

hamma printerlar scan yoki fax funksiyasini qo'llab quvvatlay olmaydi, va bu misol ISP ni buzadi.

module PrintFunctions
  def print

  end
end

module ScanFunctions
  def scan

  end
end

module FaxFunctions
  def fax

  end
end

class Samsung
  include PrintFunctions
  include ScanFunctions
end
Enter fullscreen mode Exit fullscreen mode

Endi client o'ziga kerakli methodlarni ishlata oladi.

5. Dependency Inversion Principle
High-level class'lar low level class'larga qaram bo'lmasligi kerak. Har ikkalasi ham abstraktsiyaga qaram bo'lishi kerak. Dependency Inversion Liskov Substitution and Open-Closed principlari jamlanmasi.

class NotificationService
  def notify_via_email(message)
    # EmailNotifier classga to'g'ridan to'g'ri bog'liq
    email_notifier = EmailNotifier.new
    email_notifier.send_email(message)
  end
end

class EmailNotifier
  def send_email(message)
    puts "Sending email with message: #{message}"
    # Logic to send an email
  end
end

notification_service = NotificationService.new
notification_service.notify_via_email('Hello via Email!')
Enter fullscreen mode Exit fullscreen mode

bu yerda muammolar:

  1. NotificationService EmailNotifier classga bog'liqligi
  2. Yangi Notification type qo'shmoqchi bo'lsak, NotificationService classga o'zgartirish kiritishga to'g'ri keladi. Bu muammolarni Dependency Inversion prinsipiga binoan hal qilsak:
# notifier.rb, Abstraksiya yaratish
module Notifier
  def send_message(message)
    raise NotImplementedError, 'You must implement the send_message method'
  end
end

class EmailNotifier
  include Notifier

  def send_message(message)
    puts "Sending email with message: #{message}"
    # Logic to send an email
  end
end

# notification_service.rb, Notifier abstraksiyasini ishlatish
class NotificationService
  def initialize(notifier)
    @notifier = notifier
  end

  def notify(message)
    @notifier.send_message(message)
  end
end

email_notifier = EmailNotifier.new
notification_service = NotificationService.new(email_notifier)
notification_service.notify('Hello via Email!')
Enter fullscreen mode Exit fullscreen mode

Bu bilan yuqori darajadagi class undan pastroq darajadagi classga bog'liq bo'lmaydi.

Top comments (2)

Collapse
 
der_gopher profile image
Alex Pliutau

Great write-up! Also wrote some thoughts about it but in context of Go. Although Golang is not a purely object-oriented language, we can still apply SOLID principles to improve our Go code - packagemain.tech/p/mastering-solid...

Collapse
 
shakhboz01 profile image
Shakhboz01

good job