定义

  • 依赖倒置原则是罗伯特·马丁发表的:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想:要面向接口编程,不要面向实现编程。
  • 依赖倒置是实现开闭原则的重要途经之一,他降低了客户与实现模块之间的耦合。
  • 使用接口或者抽象类的目的是制定好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给实现类。

    作用

  • 降低类间的耦合性

  • 提高系统的稳定性
  • 减少并行开发引起的风险
  • 提高代码的可读性和可维护性

    实现方法

  • 依赖倒置原则的目的是通过要面向接口的编程来降低类间的耦合性

  • 每个类尽量提供接口或者抽象类,或者两者都具备
  • 变量的声明类型尽量是接口或者是抽象类
  • 任何类都不应该从具体类派生
  • 使用继承时尽量遵循里氏替换原则

【例1】依赖倒置原则在“顾客购物程序”中的应用。
分析:本程序反映了 “顾客类”与“商店类”的关系。商店类中有 sell() 方法,顾客类通过该方法购物。

  1. // 客户通过sell()方法购物
  2. class Customer {
  3. public void shopping(ShaoguanShop shop) {
  4. //购物
  5. System.out.println(shop.sell());
  6. }
  7. }

但是,这种设计存在缺点,如果该顾客想从另外一家商店(如婺源网店 WuyuanShop)购物,就要将该顾客的代码修改如下:

  1. class Customer {
  2. public void shopping(WuyuanShop shop) {
  3. //购物
  4. System.out.println(shop.sell());
  5. }
  6. }

顾客每更换一家商店,都要修改一次代码,这明显违背了开闭原则。存在以上缺点的原因是:顾客类设计时同具体的商店类绑定了,这违背了依赖倒置原则。解决方法是:定义“婺源网店”和“韶关网店”的共同接口 Shop,顾客类面向该接口编程,其代码修改如下:

  1. class Customer {
  2. public void shopping(Shop shop) {
  3. //购物
  4. System.out.println(shop.sell());
  5. }
  6. }

这样,不管顾客类 Customer 访问什么商店,或者增加新的商店,都不需要修改原有代码了,其类图如图 1 所示。

三、依赖倒置原则 - 图1

  1. public class DIPtest {
  2. public static void main(String[] args) {
  3. Customer wang = new Customer();
  4. System.out.println("顾客购买以下商品:");
  5. // 新增商店只需实现接口,顾客只需创建对应的商店实例
  6. wang.shopping(new ShaoguanShop());
  7. wang.shopping(new WuyuanShop());
  8. }
  9. }
  10. //商店
  11. interface Shop {
  12. public String sell(); //卖
  13. }
  14. //韶关网店
  15. class ShaoguanShop implements Shop {
  16. public String sell() {
  17. return "韶关土特产:香菇、木耳……";
  18. }
  19. }
  20. //婺源网店
  21. class WuyuanShop implements Shop {
  22. public String sell() {
  23. return "婺源土特产:绿茶、酒糟鱼……";
  24. }
  25. }
  26. //顾客
  27. class Customer {
  28. public void shopping(Shop shop) {
  29. //购物
  30. System.out.println(shop.sell());
  31. }
  32. }

程序的运行结果如下:

  1. 顾客购买以下商品:
  2. 韶关土特产:香菇、木耳……
  3. 婺源土特产:绿茶、酒糟鱼……