Open-Closed Principle là một nguyên tắc viết code mà ở đó code của chúng ta sẽ Open for Extension nhưng Closed for Modification. Điều này có nghĩa chúng ta sẽ không modify code đã có có thể phá vỡ tính đúng đắn của nó mà chúng ta sẽ thêm mới code để mở rộng thêm chức năng cho ứng dụng.
Ví dụ mình muốn đánh giá xếp loại cho sinh viên bất kỳ dựa vào điểm số, mình có thể viết code như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package com.huongdankotlin.designpattern.ocp class Student { fun classify(score: Int): Classification { if (score > 9) { return Classification.EXCELLENCE } if (score > 8) { return Classification.GOOD } if (score > 6) { return Classification.NORMAL } return Classification.MEDIUM } } |
Với enum Classification có nội dung như sau:
1 2 3 4 5 6 7 8 |
package com.huongdankotlin.designpattern.ocp enum class Classification { NORMAL, MEDIUM, GOOD, EXCELLENCE } |
Những sinh viên nào có điểm số lớn hơn 9 sẽ được xếp loại excellence, lớn hơn 8 sẽ là good, lớn hơn 6 sẽ là normal và còn lại sẽ là medium. Mình sẽ chạy ví dụ như sau:
1 2 3 4 5 6 7 |
package com.huongdankotlin.designpattern.ocp fun main() { val student = Student() println(student.classify(7)) } |
Kết quả:
Sẽ không có vấn đề gì nếu trong tương lai mình lại muốn thêm một tiêu chí xếp loại nữa là nếu điểm số nhỏ hơn 5 thì sẽ xếp loại yếu. Lúc này, nếu không apply Open-Closed Principal, mình sẽ phải đi modify phương thức clarify() trong class Student để đạt được mong muốn của mình. Có thể những ứng dụng đơn giản, các bạn sẽ thấy không có gì lớn lao nếu chúng ta modify trực tiếp phương thức clarify() nhưng hễ tưởng tượng bạn đang làm việc với những ứng dụng phức tạp, mỗi khi modify các class đã tồn tại, có thể sẽ break các feature đã work trước đó của ứng dụng.
Cách viết tốt hơn trong trường hợp này với Open-Closed Principal là chúng ta sẽ thêm class đảm nhận việc xếp hạng sinh viên với điểm số nhỏ hơn 5 như sau:
1 2 3 4 5 6 7 8 9 10 11 12 |
package com.huongdankotlin.designpattern.ocp class WeakStudent: Student() { override fun classify(score: Int): Classification { if (score < 5) { return Classification.WEAK } return super.classify(score); } } |
Enum Classification cũng cần phải update như sau:
1 2 3 4 5 6 7 8 9 |
package com.huongdankotlin.designpattern.ocp enum class Classification { WEAK, NORMAL, MEDIUM, GOOD, EXCELLENCE } |
Bây giờ, sửa lại ứng dụng ví dụ sử dụng class WeakStudent:
1 2 3 4 5 6 7 |
package com.huongdankotlin.designpattern.ocp fun main() { val student = WeakStudent() println(student.classify(7)) } |
các bạn sẽ thấy kết quả như sau:
Kết quả vẫn như ở trên, nhưng nếu các bạn đổi score là 4:
1 2 3 4 5 6 7 |
package com.huongdankotlin.designpattern.ocp fun main() { val student = WeakStudent() println(student.classify(4)) } |
các bạn sẽ thấy xếp loại WEAK sẽ được trả về:
Chúng ta đã thêm tính năng cho ứng dụng nhưng đã không cần phải modify class Student đã tồn tại.