Giới thiệu
Đây là nguyên tắc cuối cùng trong 5 nguyên tắc SOLID, tương ứng với chữ D trong SOLID.
Phát biểu:
Các module cấp cao không nên phụ thuộc vào module cấp thấp, cả hai nên phụ thuộc vào interface.
Interface không nên phụ thuộc vào chi tiết mà ngược lại (Các class giaotiếp với nhau thông qua interface, không phải qua implementation)
Giải thích
Trong bài viết này mình hay dùng từ module, có thể hiểu một module có thể là một project, một service, một class.
Module cấp thấp là những module chứa những implement cơ bản và operations(disk access, network protocol,…).
Module cấp cao là những module chứa những logic phức tạp(business, flows, …) những class nảy dựa trên các module cấp thấp class để hiển thực.
Xem vd dưới đây:
public class Developer { public Developer() { } public void work() { System.out.println("Developer starting for work"); } }
public class Tester { public Tester() {} public void work() { System.out.println("Tester starting for wook"); } }
public class Manager { List developers; List testers; public Manager() { developers = new ArrayList<>(); testers = new ArrayList<>(); } public void addDeveloper (Developer developer) { this.developers.add(developer); } public void addTester(Tester tester) { this.testers.add(tester); } }
Một Manager có thể quản lý nhiều nhân viên thuộc các loại khác nhau, như là Developer, Tester, etc
Ở đây Manager là một module cấp cao, Tester, Developer là các module cấp thấp. Code ở trên sẽ vẫn chạy tốt, cho đến khi Manager của bạn có thể quản lý thêm QA, Business Analyze, thì lúc đó bạn sẽ phải đinh nghĩa thêm class QA, BusineesAnalyze, … và bạn lại phải sửa class Manager, đến đây thôi, bạn đã thấy class Manager của bạn đã vi phạm nguyên tắc Single responsibility principle và Open closed principle.
Giả sử sau này bạn cần thêm nhiều class nhân viên kiểu khác nữa thì bạn phải khởi tạp class sau đó thêm vào Manager viết thêm các chức năng cho nó etc, nó sẽ làm cho class Manager của bạn ngày một phình to và hao tốn rất nhiều thời gian để mở rộng và nâng cấp.
Áp dụng dependency inversion
Xem hình dưới đây
Mình đã tạo một class cha Employee là super class cho Tester, QA, Developer. Lúc này Manager chỉ quản lý chúng thông qua Employee. Mọi chức năng được khai báo trong Employee và được triển khai riêng trên từng class Tester, Developer etc. Manager sẽ không phải triển khai chức năng cho từng class cụ thể mà chỉ triển khai các chức năng nó thực sự cần.
Ví dụ áp dụng DIP
import java.util.ArrayList; import java.util.List; public class Manager { List<Employee> employees; public Manager() { employees = new ArrayList<>(); } public void addEmployee(Employee employee) { employees.add(employee); } }
public abstract class Employee { abstract public void work(); } // class developer public class Developer extends Employee { public Developer() { } @Override public void work() { System.out.println("Developer starting for work"); } } // class QA public class QA extends Employee { public QA() { } @Override public void work() { System.out.println("QA starting for work"); } } // class Tester public class Tester extends Employee { public Tester() {} @Override public void work() { System.out.println("Tester starting for work"); } }
Kết luận
Trong thực thế mọi người thường áp dụng Dependency Injection để đảm bảo nguyên lý DIP.
Vậy là chúng ta đã đi hết trên nguyên thiết kế hướng đối tượgn SOLID rồi đó. Hiểu đã khó, áp dụng càng khó hơn. Nếu các bạn đọc thấy hay thì hãy cố gắng đọc đi đọc lại và áp dụng nhé. Đây cũng một trong những phần đầu tiên mà các công ty lớn sẽ training cho bạn khi vừa mới bắt đầu đi làm nên hãy chuẩn bị trước thì tốt hơn nhé.