如需下载源码,请访问
https://github.com/fengchuanfang/Dependence_Inversion_Principle
文章原创,转载请注明出处:
设计模式心法之依赖倒置原则
依赖倒置原则(Dependence Inversion Principle,DIP)
——设计模式基本原则之一
定义
高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。
(High level modules should not depend upon low level modules.Both should depend upon abstractions.Abstractions should not depend upon details.Details should depend upon abstractions.)
高层模块不应该依赖低层模块,即高层模块应该持有抽象类或接口的引用,而不应该持有某一具体实现类的引用。
抽象不应该依赖细节,即接口或抽象类不应该持有某一具体实现类的引用,而应该持有此类所继承抽象类或所实现接口的引用。
细节应该依赖抽象,即实现类也应该持有抽象类或接口的引用,而不应该持有某一具体实现类的引用。
下面我们引用在设计模式心法之单一职责原则中提到过的事例来体验一下依赖倒置原则的优势。
某一产品的生产需要经过原料预处理,原料加工,产品包装,产出成品四个过程,接口如下:
//预处理接口
public interface IPreProcess {
String preProcess(String material);
}
//加工接口
public interface IProcess {
String process(String material);
}
//包装接口
public interface IPackaging {
String packaging(String semiProduct);
}
//产出成品接口
public interface IFactory {
String process(String product);
}
四个接口对应的四个实现类如下:
//原料预处理类
public class PreProcess implements IPreProcess{
@Override
public String preProcess(String material) {
return "*" + material + "——>";
}
}
//加工类
public class Process implements IProcess {
private IPreProcess preProcess;
public Process(IPreProcess preProcess) {
this.preProcess = preProcess;
}
@Override
public String process(String material) {
return this.preProcess.preProcess(material) + "加工——>";
}
}
//包装类
public class Packaging implements IPackaging {
private IProcess process;
public Packaging(IProcess process) {
this.process = process;
}
@Override
public String packaging(String material) {
return this.process.process(material) + "包装——>";
}
}
//产出成品类
public class FactoryX implements IFactory{
private Packaging packaging;
public FactoryX(Packaging packaging) {
this.packaging = packaging;
}
@Override
public String process(String material) {
return this.packaging.packaging(material)+ "产品X";
}
}
场景类中调用代码如下:
public class Client {
public static void main(String[] args) {
produce(new FactoryX(new Packaging(new Process(new PreProcess()))));
}
private static void produce(IFactory factory){
System.out.println(factory.process("原料"));
}
}
运行后,结果如下:
*原料——>加工——>包装——>产品X
从示例中我们发现,后三个过程的实现类,均持有上一个过程接口的引用,而不是某一具体实现类的引用。
这样做的好处是一旦某一过程需要变更,只需要变更这一过程所对应接口的具体实现类即可,其他过程可以不用作出更改。
例如,现在优化产品X的加工过程,采用升级后的加工方案2Process2进行加工,代码如下:
public class Process2 implements IProcess{
private IPreProcess preProcess;
public Process2(IPreProcess preProcess) {
this.preProcess = preProcess;
}
@Override
public String process(String material) {
return this.preProcess.preProcess(material) + "优化加工——>";
}
}
在场景类中只需要做微小的修改即可(不仔细看可能找不到改的哪):
public class Client {
public static void main(String[] args) {
produce(new FactoryX(new Packaging(new Process2(new PreProcess()))));
}
private static void produce(IFactory factory){
System.out.println(factory.process("原料"));
}
}
运行后发现产品X的生产过程已经采用优化后的加工方案了
*原料——>优化加工——>包装——>产品X
通过上述更改我们发现,在优化产品X的加工方案的过程中,只添加了一个加工接口的实现类Process2,其后续过程并没有发生改变,原因是后续包装过程Packaging持有的是加工过程的接口IProcess,而不是具体的某一实现类,如果将接口IProcess改为某一具体的实现类,再作出上述更改,恐怕连编译也通过不了。
如果场景类中,想调用产品Y的生产,只需要给生产方法produce(IFactory factory)传入产品Y 的实现类即可,代码如下:
public class Client {
public static void main(String[] args) {
produce(new FactoryX(new Packaging(new Process2(new PreProcess()))));
produce(new FactoryY(new Packaging(new Process(new PreProcess()))));
}
private static void produce(IFactory factory){
System.out.println(factory.process("原料"));
}
}
运行结果如下:
*原料——>优化加工——>包装——>产品X
*原料——>加工——>包装——>产品Y
方法produce(IFactory factory)依然不需要变化,便可输出想要的结果,原因是方法produce(IFactory factory)的形参接收的是接口(IFactory)类型,而不是具体的某一实现类的类型。
网友评论