Interface Segregation Principle là một nguyên tắc mà các bạn cần phải nhớ khi định nghĩa các interface sao cho chúng small nhất có thể nhưng vẫn đảm bảo cover hết tất cả các nhu cầu mà chúng ta muốn. Tránh đến việc, một class khác implement interface của các bạn nhưng lại không có nhu cầu implement detail một số phương thức của interface này vì trong context của class này, các phương thức này không có ý nghĩa.
Ví dụ, mình có một interface định nghĩa một số hoạt động của một con người như sau:
1 2 3 4 5 6 7 |
package com.huongdankotlin.designpattern.isp interface Human { fun eat() fun run() fun cook() } |
Nếu chúng ta implement interface này cho đối tượng là các trẻ em mới sinh ra thì chúng ta sẽ không cần implement phương thức run() và cook() vì chúng không thể có những hoạt động này được. Trong trường hợp này, hoặc là chúng ta sẽ phải vẫn thêm implement cho các phương thức run() và cook() nhưng không có nội dung:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.huongdankotlin.designpattern.isp class Baby : Human { override fun eat() { println("Baby is eating ...") } override fun run() { } override fun cook() { } } |
hoặc là chúng ta sẽ throw exception khi user sử dụng các phương thức này:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.huongdankotlin.designpattern.isp class Baby : Human { override fun eat() { println("Baby is eating ...") } override fun run() { throw Exception("No running implementation"); } override fun cook() { throw Exception("No cooking implementation"); } } |
Việc này sẽ gây confuse khi user sử dụng, vì mặc dù họ có thể call các phương thức run() và cook() cho đối tượng Baby nhưng không có gì với chúng ta. Chúng ta cần tránh nó!
Chúng ta có thể chia nhỏ interface Human ra thành một số interface khác, ví dụ như:
1 2 3 4 5 |
package com.huongdankotlin.designpattern.isp interface Runner { fun run() } |
và:
1 2 3 4 5 |
package com.huongdankotlin.designpattern.isp interface Cooker { fun cook() } |
Interface lúc này chỉ còn:
1 2 3 4 5 |
package com.huongdankotlin.designpattern.isp interface Human { fun eat() } |
Con người, ai cũng phải ăn! 😀
Khi đó, class Baby của chúng ta chỉ còn cần phải implement phương thức eat() mà thôi:
1 2 3 4 5 6 7 |
package com.huongdankotlin.designpattern.isp class Baby : Human { override fun eat() { println("Baby is eating ...") } } |
Nếu các bạn cần implement phương thức run() và cook() cho đối tượng là sinh viên thì các bạn chỉ cần implement các interface Runner và Cooker cho đối tượng sinh viên này là được:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.huongdankotlin.designpattern.isp class Student : Human, Cooker, Runner { override fun cook() { println("Student is cooking ...") } override fun eat() { println("Student is eating ...") } override fun run() { println("Student is running ...") } } |
Như vậy là chúng ta đã tách interface Human thành những interface nhỏ hơn, ý nghĩa hơn. Code cũng rõ ràng hơn phải không các bạn?