Nguyên lý SOLID trong lập trình hướng đối tượng

Giới thiệu

Với những developer thì chắc hẳn đã quen thuộc với khái niệm OOP với 4 tính chất:

  • Abstraction (Tính trừu tượng)
  • Encapsulation (Tính đóng gói)
  • Inheritance (Tính kế thừa)
  • Polymophirsm (Tính đa hình)

Vậy còn SOLID là gì? Hiểu đơn giản thì SOLID là 5 nguyên tắc thiết kế trong OOP giúp code chúng ta dễ đọc, dễ test và vô cùng quan trọng là dễ maintenance hơn. Những nguyên lý này được anh em developer đúc kết qua hàng chục năm fix bug nên anh em cố đọc nha 😄

1. Single Responsibility Principle

Đây là nguyên lý đầu tiên và chính là chữ S trong SOLID.

Mỗi class chỉ nên chịu trách nhiệm về 1 trách nhiệm cụ thể nào đó

Giờ ta sẽ có 1 ví dụ như sau

Class Employee
{
    function develope(){}
    function designLogo(){}
    function fixAirConditioner(){}
}

Theo như Class trên thì nhân viên ở 1 công ty sẽ có những công việc sau: develope, designLogo, fixAirConditioner. Thực chất viết thế này không sai nhưng để quản lý và phát triển code khi mà về sau có thêm nhiều công việc sẽ rất khó. Giờ mà có thêm nhân viên sale, nhân viên kế toán, nhân viên abc xyz thì chẳng lẽ ta đều cho hết vào trong Class Employee? Việc chúng ta nên làm lúc này là tách nhỏ ra từng class theo tức chức vụ riêng như Class Developer, Class Designer, ... Tuy rằng số lượng Class của ta tăng lên nhưng code sẽ được chia nhỏ ra, dễ dàng cho việc tìm kiếm và fix bug nếu cần (chắc chắn là cần rồi ý chứ 😄)

2. Open-Closed Principle

Có thể thoải mái mở rộng 1 Class nhưng không được sửa đổi bên trong nó

Tưởng tượng giờ bạn có một căn nhà, và giờ bạn muốn thêm 1 vườn thượng uyển như của các vị vua ngày xưa, bạn sẽ có 2 cách như sau:

  • Cách 1: Sửa lại căn nhà và xây thêm 1 tầng hoặc phá bỏ 1 tầng đi để xây vườn
  • Cách 2: Xây vườn ở một mảnh đất bên cạnh căn nhà

Chắc gần như mọi người đều chọn cách 2 phải không. Và nguyên lý này cũng như vậy, khi bản muốn thêm một chức năng vào 1 Class đã tồn tại trước đây, tốt nhất bạn nên tạo 1 Class khác kế thừa lại Class đó. Điều này sẽ tránh được việc làm hỏng cấu trúc của Class cũ

3. Liskov Substitution Principle

Tương ứng với chữ L trong SOLID, nguyên lý này là:

Object của Class con có thể thay thế Class cha mà không làm thay đổi tính đúng đắn của chương trình

Theo mình hiểu thì nguyên tắc này sẽ đảm bảo tính đa hình. Mình sẽ quay lại ví dụ nhân viên ở trên. Công ty sẽ phân ra 2 loại nhân viên là nhân viên chính thức và thực tập. Khác nhau sẽ là chính thức sẽ có bảo hiểm còn thực tập thì không. Giờ ở Class EmployeehaveInsurance(). Nếu Class Interns kế thừa lại Class Employee thì sẽ là sai vì thực tập không có bảo hiểm. Cách giải quyết vấn đề này thì chúng ta có thể tách hàm haveInsurance() sang một interface mới và các Class liên quan đến nhân viên chính thức có thể implements lại nó

4. Interface Segregation Principle

Thay vì dùng 1 interface lớn, ta nên tách ra thành các interface nhỏ để xử lý các vấn đề cụ thể

Cứ thử hình dung 1 interface của bạn chưa tới hàng trăm methods. Nghĩ thôi đã thấy việc đọc code khiến chúng ta muốn xóa project. Vậy nên tốt hơn cả là tách ra thành những interface nhỏ hơn

5. Dependency Inversion Principle

One should "depend upon abstractions, not concretions.

Cái này mình xin để nguyên gốc vì dịch ra sợ không rõ được nghĩa 😄. Theo nguyên lý này thì

  • Các module cấp cao không nên phụ thuộc vào các modules cấp thấp. Cả 2 nên phụ thuộc vào abstraction
  • Các class giao tiếp với nhau thông qua interface, không phải thông qua implementation.

Kết luận

SOLID là một nguyên lý nên đương nhiên bản có thể không tuân theo. Nhưng việc theo nguyên tắc này sẽ giúp chúng ta rất nhiều trong quá trình code lâu dài. Mong rằng bài viết này sẽ giúp được các bạn hiểu được phần nào nguyên tắc này.

Tham khảo: