Get in touch
or send us a question?
CONTACT

[SOLID] Open / Closed principle (OCP) – Đóng và mở

Có hai nội dung chính trong nguyên lý này:

1. Hạn chế sửa đổi: Không nên chỉnh sửa source code của một module hoặc một class có sẵn, vì sẽ làm ảnh hướng đến tính đúng đắn của chương trình.

2. Ưu tiên mở rộng: Khi cần thêm tính năng mới, nên kế thừa và mở rộng các module/class có sẵn thành các module con lớn hơn. Các module/class con vừa có các đặc tính của lớp cha (đã được kiểm chứng đúng đắn), vừa được bổ sung tính năng mới phù hợp với yêu cầu.

Thông thường, muốn có thêm chức năng, ta phải viết thêm code hoặc sửa code đã có. Tuy nhiên, nếu sửa code đã có thì lại vi phạm vào nội dung một của nguyên lý này. Vậy làm thế nào để ta có thể thiết kế một module dễ mở rộng, nhưng lại khó sửa đổi?

Trước khi nói về lập trình, hãy cùng phân tích một đồ vật trong thực tế. Tưởng tượng một chiếc máy ảnh chuyên dụng, có một ống kính đi kèm theo máy để chụp phong cảnh, giờ người dùng muốn máy ảnh có thêm tính năng chụp chân dung, thay vì đem cái ống kính đang có ra để sửa lại, chúng ta mở rộng bộ máy ảnh ra bằng dùng các ống kính khác, ví dụ như các ống kính được thiết kế để chuyên chụp chân dung. Tương tự, máy ảnh có bộ phận đèn flash nhưng công suất yếu, người dùng muốn đèn công suất cao hơn… Thay vì tháo rỡ và sửa chữa các bộ phận của máy ảnh, chúng ta có thể ráp thêm một cái flash rời.

Hình bên dưới là một chiếc máy ảnh được thiết kế đúng chuẩn theo nguyên lý Open / Closed principle (OCP). Dễ thấy, máy ảnh được thiết kế để dễ dàng mở rộng tính năng mà không cần mổ sẻ tháo lắp các bộ phận bên trong nó. Một module phù hợp OCP cũng nên được thiết kế như thế.

Áp dụng nguyên lý trong lập trình

Giả sử trường học có 2 loại sinh viên nữa: Sinh viên tài năng và du học sinh. Sinh viên tài năng được giảm 20% học phí, du học sinh tăng 30% so với học phí của sinh viên bình thường. Điều này dẫn đến phải thay đổi xử lý phần tính học phí cho sinh viên, có hai cách để giải quyết vấn đề này.

Cách thứ nhất là thêm thuộc tính loại sinh viên cho class SinhVien, sửa code trong hàm tinhHocPhi() để cho ra kết quả phù hợp với từng loại sinh viên.

Dễ thấy nếu làm theo cách này, nếu trong tương lai có thêm nhiều loại sinh viên khác, code lại phải thay đổi, có thể dẫn đến code mới làm ảnh hưởng đến code cũ và làm hỏng luôn cả những dòng code trước đó đã chạy được.

Để giải quyết vấn đề cách thứ nhất gây ra, cách thư hai áp dụng nguyên lý đóng và mở (Open / Closed principle – OCP): hạn chế sửa đổi, ưu tiên mở rộng hay nói cách khác, code được thiết kế để sau này dù có thêm yêu cầu mới cũng không phải quay lại chỉnh sửa code cũ. Code được xây dựng như sau:

Trong tương lai, khi có thêm loại sinh viên hoặc yêu cầu nào mới, ta chỉ cần tạo thêm class kề thừa từ class SinhVien ban đầu mà không làm ảnh hưởng gì đến những class có sẵn. Đảm bảo tính đúng đắn cho chương trình, hạn chế được phạm vi test, giúp giảm chi phí phát triển và bảo trì chương trình dễ dàng hơn.

Kết luận

Khi thiết kế một phần mềm, cần chú ý tới khả năng bảo trì và mở rộng của nó. Khi tạo ra các lớp hoặc một module nào đó, hãy luôn đặt câu hỏi: code thế này đã tách bạch chưa? Làm thế này có thể dễ dàng mở rộng trong tương lai? Nếu có thì làm như thế nào? … Bằng cách đó, chúng ta luôn đặt vấn đề để cải tiến phần mềm của mình.

Việc thiết kế các lớp dựa trên nguyên lí 2 của SOLID giúp phần mềm của chúng ta dễ bảo trì và dễ mở rộng hơn rất nhiều. Tất nhiên không phải lúc nào ta cũng không được chỉnh sửa code có sẵn, tuy nhiên thông thường thì chúng ta không nên làm như vậy. Tóm lại, SOLID là một guideline tốt giúp bạn thiết kế và lập trình tốt hơn.