S.O.L.I.D – Phần 1: Single Responsibility

2 min read

s.o.l.i.d Single Responsibility

Giới thiệu:

Nguyên tắc S.O.L.I.D được giới thiệu bởi Robert C. Martin, còn được biết đến với biệt danh Uncle Bob, trong bài báo của ông năm 2000 có tiêu đề “Nguyên tắc Thiết kế và Mẫu Thiết kế.” Các khái niệm này sau đó được phát triển bởi Michael Feathers, người đã giới thiệu cho chúng ta thuật ngữ S.O.L.I.D. Và trong 20 năm qua, năm nguyên tắc này đã làm thay đổi cách chúng ta viết phần mềm trong lĩnh vực lập trình hướng đối tượng, thay đổi cách chúng ta viết code.

Uncle Bob cũng là tác giả của các cuốn sách bán chạy Clean Code và Clean Architecture, và là một trong những người tham gia của “Liên minh Agile.” Do đó, không có gì ngạc nhiên khi tất cả các khái niệm về việc viết mã sạch, kiến trúc hướng đối tượng và mẫu thiết kế đều somehow liên quan và bổ trợ lẫn nhau.

Tất cả đều phục vụ một mục tiêu chung:

“Tạo ra mã nguồn dễ hiểu, dễ đọc và dễ kiểm tra mà nhiều nhà phát triển có thể cùng làm việc.”

5 nguyên tắc S.O.L.I.D bao gồm:

  1. Single Responsibility
  2. Open and Closed
  3. Liskov substitution
  4. Interface segregation
  5. Dependency inversion

Trong bài viết này, bạn sẽ cố gắng hiểu từng nguyên tắc một với các ví dụ.

1. Nguyên tắc Single responsibility (SRP)

Nguyên tắc SRP chỉ ra rằng một lớp chỉ nên có một lý do để thay đổi, có nghĩa rằng một lớp chỉ nên có một nhiệm vụ duy nhất. Nói cách khác, một lớp nên chỉ có một nhiệm vụ duy nhất và chỉ có một lý do để thay đổi.

Hãy xem xét ví dụ với lớp Invoice:

class Invoice {
    let book: Book
    let quantity: Int
    let discountRate: Int
    let taxRate: Float
    var total: Float = 0.0
    
    init(book: Book, quantity: Int, discountRate: Int, taxRate: Float) {
        self.book = book
        self.quantity = quantity
        self.discountRate = discountRate
        self.taxRate = taxRate
        self.total = self.calculateTotal()
    }

    public func calculateTotal() -> Float {
        let price = ((book.price - book.price * discountRate) * quantity)
        let priceWithTaxes = Float(price) * (1.0 + taxRate)
        return priceWithTaxes
    }

    public func printInvoice() {
        print("\(quantity) x \(book.name)         \(book.price)$")
        print("Discount Rate: \(discountRate)")
        print("Tax Rate: \(taxRate)")
        print("Total: \(total)")
    }

    public func saveToFile(filename: String) {
        // Tạo một tệp với tên được cho và ghi hóa đơn vào tệp đó
    }
}

Lớp Invoice vi phạm nguyên tắc SRP vì nó xử lý các tính toán, in và lưu vào tệp. Để tuân thủ SRP, chúng ta có thể tạo ra các lớp riêng biệt cho việc in và lưu trữ:

class InvoicePrinter {
    let invoice: Invoice
    
    init(invoice: Invoice) {
        self.invoice = invoice
    }

    public func printInvoice() {
        // In chi tiết hóa đơn
    }
}

class InvoicePersistence {
    let invoice: Invoice
    
    public init(invoice: Invoice) {
        self.invoice = invoice
    }

    public func saveToFile(filename: String) {
        // Lưu hóa đơn vào tệp
    }
}

Bây giờ mỗi lớp sẽ đảm nhiệm 1 nhiệm vụ duy nhất để luôn tuân thủ nguyên tắc Single responsibility

Tham khảo:

https://www.codeproject.com/Articles/703634/SOLID-architecture-principles-using-simple-Csharp

https://scotch.io/bar-talk/s-o-l-i-d-the-first-five-principles-of-object-oriented-design

https://nhungdongcodevui.com/2017/03/25/solid-la-gi-nguyen-tac-2-dong-va-mo-open-closed-principle-ocp/

Avatar photo

Leave a Reply

Your email address will not be published. Required fields are marked *