Dependency Inversion Principle là một nguyên tắc viết code mà theo định nghĩa thì các module cấp cao không nên phụ thuộc vào các module cấp thấp, chúng chỉ nên phụ thuộc vào abstraction và interface không nên phụ thuộc vào implementation mà nên là ngược lại. Nó sẽ hơi khó hình dung cho những bạn mới bắt đầu nhưng mình có thể nói nôm na như thế này: các class muốn lấy thông tin từ các class khác, ví dụ như lấy thông tin từ database chẳng hạn thì nên thông qua một interface hoặc một abstract class. Implementation của interface hay abstract class này sẽ đảm nhận việc lấy thông tin giúp cho bạn. Và tất nhiên là implementation chỉ nên phụ thuộc vào interface, không nên có chiều ngược lại các bạn nhé!
Ví dụ như mình có một ứng dụng lấy thông tin sinh viên. Nếu không apply Dependency Inversion Principle, các bạn có thể gọi trực tiếp để lấy thông tin như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
package com.huongdankotlin.designpattern.dip fun main() { val studentRepository: StudentRepository = StudentRepository(); val student = studentRepository.findById(1); println(student?.name) } class StudentRepository() { var students: List<Student> = ArrayList() init { students = arrayListOf(Student(1, "Khanh"), Student(2, "Quan")) } fun findById(id: Int): Student? { for (student: Student in this.students) { if (student.id == id) { return student } } return null } } class Student(var id: Int, var name: String) { } |
Kết quả khi chạy ví dụ:
Các bạn hãy thử tưởng tượng và suy nghĩ xem, nếu bây giờ mình cần lấy thông tin sinh viên từ database, có phải là mình cần phải viết lại hết code không?
Để tránh điều này, và dễ dàng thay đổi nhu cầu nếu muốn, chúng ta nên sử dụng interface để lấy thông tin sinh viên như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package com.huongdankotlin.designpattern.dip fun main() { val studentRepository: StudentRepository = StudentRepo1(); val student = studentRepository.findById(1); println(student?.name) } interface StudentRepository { fun findById(id: Int): Student? } class StudentRepo1(): StudentRepository { private var students: List<Student> = ArrayList() init { students = arrayListOf(Student(1, "Khanh"), Student(2, "Quan")) } override fun findById(id: Int): Student? { for (student: Student in this.students) { if (student.id == id) { return student } } return null } } class Student(var id: Int, var name: String) { } |
Ở đây, mình đã giới thiệu một interface StudentRepository với phương thức findById() và class StudentRepo1 là class implement interface này. Trong tương lai, nếu các bạn muốn lấy thông tin sinh viên từ database chẳng hạn, các bạn chỉ cần tạo một class mới implement interface StudentRepository này là xong. Code của chúng ta sẽ không cần sửa nhiều mà vẫn đảm bảo tính đúng đắn của code cũ.