1.依赖倒转原则是什么?
依赖倒转原则也被称为依赖倒置原则,它的原始定义是: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。翻译过来主要包含两层含义:
- 高层模块不应依赖于低层模块,二者都应依赖于抽象
- 抽象不应依赖于细节,细节应该依赖于抽象
其实更为简洁的定义就是,在进行面向过程的编程中,我们需要针对抽象编程,而不是针对细节编程。这句话听起来有些绕口,第一次接触这个概念的人此时一定是一脸懵逼的状态,就用我们平常最常用的计算机举例子,在计算机的内部首先会有一个主板,在主板上会有CPU、内存、显卡、硬盘等,如果此时内存坏了,我们就需要针对主板上的内存接口重新换一个新的内存就可以解决问题,这里的设计就是生产内存的厂家针对接口(抽象)在生产内存,如果内存厂家是针对实现(细节)来生产内存,内存就要具体到针对某个品牌某个型号的主板,那么换内存就有可能出现把整个主板都换了的尴尬场面。可见我们的生活中处处都存在面向对象设计的思想,这种面向接口编程—OOD(Object-Oriented Design)是面向对象设计思想的精髓之一。
2.在代码中实现
这里使用司机开车的例子来进行说明
新建一个奔驰车的类,奔驰车提供一个run()方法
package CommonDesign;
/**
* 奔驰车的类
* Created by ChuPeng on 2017/2/19.
*/
public class Benz
{
public void run()
{
System.out.println("奔驰车开始启动...");
}
}
新建一个司机类,司机通过driver()的方法可以开动汽车
package CommonDesign;
/**
* 司机的类
* Created by ChuPeng on 2017/2/19.
*/
public class Driver
{
public void dirve(Benz benz)
{
benz.run();
}
}
在实际应用场景中
package CommonDesign;
/**
* 具体实现的类
* Created by ChuPeng on 2017/2/19.
*/
public class Client
{
public static void main(String[] args)
{
Driver driver = new Driver();
Benz benz = new Benz();
//司机开动奔驰
driver.dirve(benz);
}
}
通过以上的代码就完成了模拟司机开车的的场景,可是这个问题来了如果这时再加上其他车的种类,比如奥迪车和宝马车,司机的类就不能胜任了,因为在司机的类中只有启动奔驰车的方法并没有启动奥迪车或者宝马车的方法,有的人就说了我们可以重写司机类中的方法,使其有启动奥迪车或者宝马车的方法。这里要注意的是如果对司机类进行修改就违背了开放—封闭原则,所以在我们开始进行程序设计的过程中要对抽象进行编程而不是对细节进行编程。
遵循依赖倒转原则进行修改,分别通过建立汽车和司机的两个接口来定义各自的职能
package DependenceInversionPrincipleDesign;
/**
* 汽车的接口
* Created by ChuPeng on 2017/2/19.
*/
public interface ICar
{
public void run();
}
package DependenceInversionPrincipleDesign;
/**
* 司机的接口
* Created by ChuPeng on 2017/2/19.
*/
public interface IDriver
{
public void driver(ICar car);
}
这里的接口只是一个抽象化的概念,是对一类事物的抽象的描述,具体的实现由相应实现的类中来完成,所以这里还需要新建汽车类和司机类
package DependenceInversionPrincipleDesign;
/**
* 奔驰车的类实现汽车的接口,重写run()方法
* Created by ChuPeng on 2017/2/19.
*/
public class Benz implements ICar
{
public void run()
{
System.out.println("奔驰车开始启动...");
}
}
package DependenceInversionPrincipleDesign;
/**
* 宝马车的类实现汽车的接口,重写run()方法
* Created by ChuPeng on 2017/2/19.
*/
public class BMW implements ICar
{
public void run()
{
System.out.println("宝马车开始启动...");
}
}
package DependenceInversionPrincipleDesign;
/**
* 奥迪车的类实现汽车的接口,重写run()方法
* Created by ChuPeng on 2017/2/19.
*/
public class Audi implements ICar
{
public void run()
{
System.out.println("奥迪车开始启动...");
}
}
package DependenceInversionPrincipleDesign;
/**
* 司机的类实现司机的接口,重写driver()方法
* Created by ChuPeng on 2017/2/19.
*/
public class Driver implements IDriver
{
public void driver(ICar car)
{
car.run();
}
}
在实际的应用场景中
package DependenceInversionPrincipleDesign;
/**
* 具体实现的类
* Created by ChuPeng on 2017/2/19.
*/
public class Client
{
public static void main(String[] args)
{
Driver driver = new Driver();
Benz benz = new Benz();
BMW bmw = new BMW();
Audi audi = new Audi();
driver.driver(benz);
driver.driver(bmw);
driver.driver(audi);
}
}
这样如果在增加新的车型我们只需要新建对应的类并行实现汽车接口,在实际场景中使用即可。
3.总结
在整个业务场景中,我们使用贯彻“抽象不应该依赖细节,细节应该依赖抽象”和“高层模块和低层模块都应该依赖于抽象”,也就是我们认为抽象(ICar接口)不依赖BMW和Benz两个实现类(细节),因此我们在高层次的模块中应用都是抽象。 Client属于高层业务逻辑,它对低层模块的依赖都建立在抽象上,在IDriver中,通过传入ICar接口实现了抽象之间的依赖关系,Driver实现类也传入了ICar接口,至于到底是哪个型号的Car需要在高层模块中声明。
以上Demo的源代码地址:点击打开链接