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
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
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
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
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
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
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
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!')
bu yerda muammolar:
- NotificationService EmailNotifier classga bog'liqligi
- 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!')
Bu bilan yuqori darajadagi class undan pastroq darajadagi classga bog'liq bo'lmaydi.
Top comments (2)
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...
good job