SOLID – Thiết kế code chuyên nghiệp

solid objects oriented design

solid-object-oriented-design

Chắc hẳn lập trình viên nào trong số chúng ta cũng đều biết đến khái niệm lập trình hướng đối tượng (OOP). Đây là một mô hình lập trình rất phổ biến hiện nay và xuất hiện trên hầu hết các ngôn ngữ lập trình hiện đại. OOP giúp tăng năng suất, đơn giản hóa việc bảo trì cũng như mở rộng phần mềm.

SOLID là tổ hợp các nguyên lý thiết kế trong lập trình hướng đối tượng. Khi áp dụng các nguyên lý này, phần mềm của bạn sẽ có một kiến trúc tốt và thực sự “dễ bảo trì” và “dễ mở rộng“. SOLID được phát biểu bởi ông Robert C. Martin, tên thân mến là : “Uncle Bob“.

S.O.L.I.D BAO GỒM: 

  • Single Responsibility Principle
  • Open-Closed Principle
  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Dependency Inversion Principle

Trong phạm vi bài viết này, tôi xin trình bày về 2 nguyên lý đầu tiên là Single Responsibility Principle và Open-Closed Principle.

Phần 1: Single Responsibility principle (SRP)

unnum_8_1

Uncle Bob: A class should have one, and only one, reason to change.

Tôi dịch: Mỗi class chỉ có một nhiệm vụ duy nhất, chỉ sửa đổi class với một lý do duy nhất. Nếu có tới 2 lý do để sửa class thì class đó chưa đạt yêu cầu.

Đề bài: Lớp Boy được truyền giá trị đầu vào là “$person”. Ta cần kiểm tra xem “$person” có phải là nữ không. Nếu là nữ thì Boy có thể “chich”.

s1

Thoáng nhìn qua thì đoạn code phía bên tay trái có thể đáp ứng đầy đủ yêu cầu đề bài. Tuy nhiên nó không thỏa mãn nguyên lý thứ nhất trong SOLID (SRP). Lớp Boy phải làm 2 việc không mấy liên quan đến nhau: Vừa phải “chich”, vừa phải kiểm tra xem “$person” có phải nữ hay không ( Hàm “isGirl()”).

Việc kiểm tra giới tính không phải là chuyên môn của Boy, làm sao có thể biết chính xác được “$person” có phải nữ không? Thế là anh Boy này mới tìm đến ông bác sĩ tên là “GenderChecker”. Ông này có đủ kiến thức và máy móc để xác định chính xác giới tính của “$person”. Sau khi kiểm tra xong ông ấy sẽ báo cáo kết quả lại cho Boy. Boy nhận được kết quả từ ông bác sĩ thì sẽ quyết định “chich” hay dừng lại. Đó là thứ tôi trình bày ở đoạn code bên tay phải – Mỗi lớp chỉ thực hiện một nhiệm vụ duy nhất.

Phần 2: Open-Close principle (OCP)

open-closed-principle-kata-7-638

Uncle Bob:You should be able to extend a classes behavior, without modifying it.

Tôi dịch: Class, module, function có thể thoải mái mở rộng nhưng không được sửa chúng.

Ví dụ: Có 2 người từ 2 nước khác nhau: Việt Nam, Hàn Quốc.

Giai đoạn 1 của dự án: In ra màn hình nội dung chữ “Xin chào” bằng tiếng Anh.

Giai đoạn 2 của dự án: In ra màn hình nội dung chữ “Xin chào” bằng tiếng mẹ đẻ.

  1. Theo lối thông thường, tôi xin phép code giai đoạn 1 như sau:
Không cần quan tâm tới người nước nào, chỉ cần in ra “Hello”.

         2.  Sau khi chuyển sang giai đoạn 2 của dự án . Ta phải sửa code trong lớp Hello như sau:

Ở giai đoạn này, tôi đã vi phạm OCP . Lớp Hello phụ thuộc vào lớp Vietnamese và Korean. Nếu Vietnamese thay đổi ngôn ngữ thì lớp Hello cũng phải thay đổi theo. Tức là khi sửa một lớp thì nó làm ảnh hưởng tới lớp khác.

3. Code sau khi đã làm theo OCP:

Lớp Hello sẽ không phụ thuộc vào lớp Korean và Vietnamese nữa. Nếu 2 người nước này có thay đổi ngôn ngữ thì chỉ sửa đổi trong bản thân 2 lớp này chứ không phải sửa code ở lớp Hello.

Trên đây là ý kiến cá nhân của tôi về 2 nguyên lý đầu tiên trong SOLID: Single Responsibility Principle và Open-Closed Principle. Thông qua các ví dụ cụ thể, tôi hi vọng rằng các bạn có thể hiểu rõ ý đồ của mình.  Nếu có ý kiến đóng góp, vui lòng để lại dưới comment!

4 Replies to “SOLID – Thiết kế code chuyên nghiệp

  1. Một sự cẩu thả đáng trách trong các lấy ví dụ. Nếu thật sự viêt bài (cho dù chỉ để cho nội bộ đọc) cũng cần có tâm 1 chút.
    về phần 1 đoạn code đc đánh “GOOD” : Khi 1 boy thực thi method chich thì sẽ chich person nào? property của nó? OK nếu thế thì phải là $this->person. Kiểu dữ liệu của $person là gì? Tôi truyền null vào thì đoạn code của bạn sấp mặt ngay.
    Ngoài ra thì tại sao 1 boy lại cần có property là $person? 1 boy chỉ có 1 $person nên nó cũng “chỉ có thể chich” duy nhất $person đấy =)). Ấy là còn chưa kể 1 thằng gender_checker lại được truy cập vào thuộc tính của $person thế có nghĩa là nó cũng thay đổi được giá trị (kiểu như là 1 thằng đc sinh ra với chức năng kiểm tra giới tính có thể phẫu thuật chuyển giới =)) ) nguy cơ vi phạm chính SRP là hiển hiện trước mắt. =))
    OK “tái cấu trúc” lại 1 tí nhé: thêm 1 abtract class Person vào này, class này có PRIVATE property là gender. Boy sẽ extends Person. Theo mình hiểu thì chỉ các boy mới có thể chich và chỉ có thể chich các person có gender là “female” nên sẽ có thêm 1 class Girl extends Person và gender = female + không có function chich. Đơn giản là truyền 1 $girl kiểu dữ liệu Girl vào function chich().

    1. Chào bạn, những đóng góp của bạn rất hữu ích.
      Về phía tác giả khi viết bài này, tôi mong muốn ít code nhất có thể để mọi người dễ hiểu vấn đề tôi tập trung tới.
      Ở các bài viết tới, tôi sẽ cố gắng viết cẩn thận hơn.
      Cảm ơn bạn!

      1. ” tôi mong muốn ít code nhất có thể để mọi người dễ hiểu vấn đề tôi tập trung tới”
        Nói thì có vẻ như là “Tôi biết nhưng tôi sợ cao siêu quá thì mọi người không hiểu” nhưng thực ra là “BẠN chưa hiểu 1 cách thấu đáo”.
        Nói bạn đừng buồn chứ cái cách bạn lấy ví dụ không những thể hiện sự hiểu biết qua loa về S.O.L.I.D mà ngay cả kiến thức cơ bản về OOP cũng không vững.
        Đừng cố ngụy biện, nhận sai và sửa chữa đi

Leave a Reply

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