依赖倒置原则定义,及倒置的两种理解
2018-03-06 11:33
525 查看
依赖倒置原则定义
如下(可先不管)- 高层模块不应该依赖低层模块,两者都应该依赖抽象
- 抽象不应该依赖细节
- 细节应该依赖抽象
情景描述
当前有一家饮料店,里面卖着很多饮料设计如下
问题描述
这里箭头符号表示BeverageStore依赖Juice,及高层依赖于低层
在BeverageStore中,对应的是具体的饮料实现,具体代码如下
package headfirst.hd.dep; public class BeverageStore { //卖果汁 public Juice saleBeverage() { //果汁的具体实现 Juice juice = new Juice(); return juice; } }
修改设计,为饮料提供统一接口
备注:这是网上很多教程讲的例子,根据我自己的理解,这不是依赖倒置的体现,后来我会给出原因
核心代码变为一下代码,依赖变为不仅依赖低层组件的实现,而且还依赖低层组件的抽象,比之前还更糟糕
package headfirst.hd.dep; public class BeverageStore { //卖果汁 public Beverage saleBeverage() { //果汁的具体实现 Beverage beverage = new Juice(); return beverage; } }
对这个代码再优化一下
package headfirst.hd.dep; //这是网上最常见方式 public class BeverageStore { //卖果汁 public Beverage saleBeverage(Beverage beverage) { //做一些其他操作 return beverage; } }
客户端Client
package headfirst.hd.dep; public class Client { public static void main(String[] args) { BeverageStore store = new BeverageStore(); store.saleBeverage(new Juice()); } }
对应设计变化为
高层依赖低层还是曾在,并且由更高层依赖了低层模块
我个人觉得这应该叫依赖转移
引入工厂方法模式改进以上例子
工厂模式设计图核心代码
BeverageStore
package headfirst.hd.dep; //工厂方法模式 public abstract class BeverageStore { //卖果汁 public Beverage saleBeverage() { //直接使用自身定义的抽象方法 Beverage beverage = createBeverage(); //做一些其他操作 return beverage; } /** * 抽象类BeverageStore抽象方法定义,Beverage createBeverage() * 表明createBeverage与BeverageStore为一体,关系为一根横线, * 两者没有实质依赖关系,因为在BeverageStore中,直接使用自身 * 定义方法createBeverage,在类BeverageStore的其他方法中, * 直接使用该类型,具体实现具体类,延迟到子类 */ abstract Beverage createBeverage(); }
BeverageStoreFactory
package headfirst.hd.dep; //工厂方法模式 public class BeverageStoreFactory extends BeverageStore{ @Override Beverage createBeverage() { //可传入参数,得到更多实例, //或者BeverageStoreFactory2,多个工厂方法,都可以 return new Juice(); } }
测试Client
package headfirst.hd.dep; public class Client { //优秀啦,一点都没有低层模块代码 public static void main(String[] args) { BeverageStore store = new BeverageStoreFactory(); store.saleBeverage(); } }
理解加入模式前后的不同
加入前加入后
主要区别体现在两点
store与product关系
加入工厂前,实际上还是具有依赖关系,实质上将依赖关系往更高层转移
package headfirst.hd.dep; //这是网上最常见方式 public class BeverageStore { //卖果汁 public Beverage saleBeverage(Beverage beverage) { //做一些其他操作 return beverage; } }
加入工厂后
//工厂方法模式 public abstract class BeverageStore { //卖果汁 public Beverage saleBeverage() { //直接使用自身定义的抽象方法 Beverage beverage = createBeverage(); //做一些其他操作 return beverage; } /** * 抽象类BeverageStore抽象方法定义,Beverage createBeverage() * 表明createBeverage与BeverageStore为一体,关系为一根横线, * 两者没有实质依赖关系,因为在BeverageStore中,直接使用自身 * 定义方法createBeverage,在类BeverageStore的其他方法中, * 直接使用该类型,具体实现具体类,延迟到子类 */ abstract Beverage createBeverage(); }
所有加入前还是具有依赖关系,所以是箭头,加入工厂模式之后,为接口定义,为一体,所以属于直线
2. storefactory取代了Client位置
加入前层级关系
加入后层级关系
倒置的两种理解
第一种,从设计上理解
如果所示,正常都是高层调用低层,简单推理一下
product1(具体的实现)依赖于product(抽象)
由于引入工厂模式后,store与product为同一关系(同时存在)
推理出,product1(具体的实现)依赖于store
因此,形成了依赖倒置的现象
第二种,从思想上理解
没有引入工厂方法模式之前,我们需要一杯果汁(Juice),我们的思路时候这样的先有一个饮料店(BeverageStore),然后才会有果汁(Juice),简单的说就是先有饮料店,最后决定卖什么饮料
引入工厂方法模式之前,我们需要一杯果汁(Juice),我们的思路时候这样的
先定义饮料接口,后实现具体的饮料店,这些我们可以理解为,我们先选择什么要的饮料,最后决定开什么样的饮料店
因此,形成了依赖倒置的现象
相关文章推荐
- 深入理解JavaScript系列(22):S.O.L.I.D五大原则之依赖倒置原则DIP详解
- 线性代数(3)矩阵与向量的乘积的两种理解
- faster rcnn:assert (boxes[:, 2] >= boxes[:, 0]).all()分析塈VOC2007 xml坐标定义理解
- 函数两种定义方法的区别
- 音乐本体中对work的定义和理解
- 如何理解极限的定义
- 定义字符串的两种方式
- 取模运算在数学定义与机器理解的区别
- C++中的声明,定义和赋值几个概念的理解
- 定义错误或异常页面的两种方式
- 用类名做方法的返回值类型 在学习Java的初始阶段,很多同学使用基本数据类型定义变量和引用类型定义变量以及使用类名做方法的返回值类型常常不知所以。今天我以自己的解读方式和个人的理解作一个简单的解释,和
- C#定义常量的两种方法
- 如何理解DocType? 什么是严格模式与混杂模式?如何触发这两种模式?
- 委托类型定义时new和直接赋值两种方式
- CTL_CODE 定义说明(重要理解内容)
- 理解生产者和消费者,两种实现方式
- EM算法的两种理解角度
- 深入理解JavaScript系列(22):S.O.L.I.D五大原则之依赖倒置原则DIP
- 结构体的两种定义方式
- 【iOS开发-72】设置状态栏的两种方式、程序生命周期以及更好地理解几大类(对象)之间的关系