依赖倒转原则的定义——程序的高层模块不应依赖于底层模块,但两者都应依赖于抽象;抽象不应该依赖于具体细节,而细节应该依赖于抽象。也就是说,面向对象编程应该针对接口编程而不是针对实现编程。
在开发中使用依赖倒转原则需要遵循以下规范:
- 每个类都尽量继承自接口或者抽象类,有了抽象才有可能依赖倒转
- 变量显示的类型尽量(不是一定)是接口或者抽象类
- 类尽量避免从具体类派生,当然如果是在项目维护阶段,基本上可以不考虑这个原则。
- 尽量不要覆盖基类的方法,如果基类是一个抽象类而且已经实现了,子类尽量不去覆盖。类之间的依赖是抽象,覆盖抽象方法,对依赖的稳定性会产生一定的影响。
在找工作的时候很多人在面试前会找各种各样的面试题,然后记下来,但是现实往往很残酷,面试官如果换一个问题或者问法就会导致面试者手忙脚乱,究其原因就是在准备面试的时候过于依赖具体的细节而不是这些问题中的思想核心。在编程中,用那种语言编程其实并不太重要,只要编写代码的时候考虑针对抽象进行编程而不是针对细节,程序中所有的依赖关系都终止于抽象类或者接口,才是真正的面向对象编程。
传统的过程性系统设计办法更倾向于使高层次模块依赖于低层次模块,抽象的层次依赖于具体的层次。倒转原则的意义就是把这个错误的依赖关系倒转过来。面向对象设计最重要的原则就是创建抽象化,同时从抽象化导出具体化,具体化给出不同实现。继承的关系就是一种从抽象化到具体化的实现。
/**
* Author:小青
* Time:2017-8-27
* Function:员工
*
*/
public class Worker{
public void work(){
System.out.println("爱工作么,爱生活,爱自己");
}
}
/**
* Author:小青
* Time:2017-8-27
* Function:经理
*
*/
public class Manager{
private Worker m_worker;
public void setWorker(Worker m_worker){
this.m_worker = m_worker;
}
public Worker getWorker(){
return m_worker;
}
public void manager(){
m_worker.work();
}
}
/**
* Author:小青
* Time:2017-8-27
* Function:高级工作者
*
*/
public class SeniorWorker{
public void work(){
System.out.println("高级工作者");
}
}
以上是一个没有遵从依赖倒转原则的实例,如果经理类是一个功能很复杂的类,当新增一个高级工作者的时候,我们需要修改经理类,同时要重新进行单元测试,而完成这些都需要不小的开销,所以看下如果支持依赖倒转,情况会有什么变化
/**
* Author:小青
* Time:2017-8-27
* Function:工作者接口
*
*/
public interface IWorker{
public void work();
}
/**
* Author:小青
* Time:2017-8-27
* Function:员工
*
*/
public class Worker implements IWorker{
public void work(){
System.out.println("爱工作么,爱生活,爱自己");
}
}
/**
* Author:小青
* Time:2017-8-27
* Function:经理
*
*/
public class Manager{
private IWorker m_worker;
public void setWorker(IWorker m_worker){
this.m_worker = m_worker;
}
public IWorker getWorker(){
return m_worker;
}
public void manager(){
m_worker.work();
}
}
/**
* Author:小青
* Time:2017-8-27
* Function:高级工作者
*
*/
public class SeniorWorker implements IWorker{
public void work(){
System.out.println("高级工作者");
}
}
这样可以明显看到,即使新增一个高级工作者,对代码的影响也是很小的。
以上内容,整理自刘径舟,张玉华编著的《设计模式其实很简单》读书笔记,欢迎转载.