定义:
High level modules should depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.
表述的是:
高层模块不应该依赖低层模块,两者都应该依赖于抽象。
抽象不应该依赖细节。
细节应该依赖抽象。
抽象:即抽象类或者接口。两者不能实例化。
细节:即具体的实现类,实现接口或者继承抽象类所产生的类,两者可以通过关键字new直接被实例化。
简单的说就是:要针对接口编程,不要针对实现编程。其本质就是通过抽象使各个类或者模块实现彼此独立,不相互影响,降低模块间的耦合,便于扩展和修改。
实例:工人有许多类别,有清洁工人,有建筑工人等。他们虽然都是工人的类别,但是不同的工人使用的工具显然是不同的。
新建工人接口,提供工具的方法:
public interface Worker {
public void userTool(Tool t) ;
}
新建工具类(其实本来该是接口,这里简单点):
public class Tool {
//工具名称
private String name;
public Tool(String s) {
this.name = s;
}
public String getName(){
return name;
}
}
然后清洁工人实现工人接口,拥有使用工具的方法:
public class Cleaner implements Worker {
private String name;
public Cleaner(String name) {
this.name = name;
}
@Override
public void userTool(Tool t) {
// TODO Auto-generated method stub
System.out.println(name + " 使用 :" + t.getName());
}
}
测试:
public class TMain {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
// 将对象传给接口
Worker cleaner = new Cleaner("张三");
Tool tool = new Tool("笤帚");
cleaner.userTool(tool);
}
}
这里,有个抽象工人类,而具体的工人类都是它的实现。在新建的对象中,将具体的实现传递给抽象。以后有什么建筑工人之类的,就可以直接实现工人接口。
依赖的3种使用方法:
1.构造方法传递依赖对象
在类中通过构造方法声明依赖对象。
public class Cleaner implements Worker {
public Cleaner(String name) {
this.name = name;
}
name就是依赖的对象,这里是字符串对象,也可以是其他对象。
2.setter方法传递依赖对象
在抽象中设置setter方法声明依赖关系
public interface Worker {
public void setter(Tool tool);
在外部调用setter方法,向对象传递依赖的对象。
3.接口声明依赖对象
在接口方法中声明依赖对象
public interface Worker {
public void userTool(Tool t);
}
t就是依赖的Tool类的实例,在具体的工人对象中传递Tool类对象。
也许原则比较抽象,那么我们在使用中遵循以下规则就能达到该效果:
1.每个类尽量有接口或者抽象类,或者抽象类和接口两者具备。这是依赖倒置原则的基本要求,接口和抽象类是属于抽象的,有了抽象才可能依赖倒置。
2.变量的显示类型尽量使接口或者抽象类。不是说绝对,工具类就不必有接口或者抽象。
3.任何类都不该从具体类派生。
4.尽量不要覆写基类的方法。类间的依赖是抽象,如果覆写了抽象方法,对依赖的稳定性会产生影响。
5.结合理是代换原则使用。里氏替换原则讲的是父类出现的地方子类就能出现,再结合里氏代换原则,可以得出这样一个通俗的规则: 接口负责定义public属性和方法,并且声明与其他对象的依赖关系,抽象类负责公共构造部分的实现,实现类准确的实现业务逻辑,同时在适当的时候对父类进行细化。