4. 依赖倒置原则
高层模块不应该依赖于低层模块。二者都应该依赖于抽象。
抽象不应该依赖于细节,细节应该依赖于抽象。
抽象层次包含的是应用系统的商务逻辑和宏观的战略性决定,而具体层次含有的是和实现有关的算法与逻辑,具体层次的代码会经常发生变动,不能避免出现错误。所以便应该是高层的策略设置模块影响低层的细节实现模块,而不是相反。比如说,先制定业务逻辑的规则,再实现数据库操作等等细节。
比较合适的模型是:每个较高的层次都为它需要的服务声明一个抽象接口,较低的层次实现这个接口,每个高层类都通过该抽象接口使用下一层。换句话来说,由客户类声明它们需要的服务接口,仅当客户需要时才对接口进行改变,所以改变实现细节的类就不会影响到客户。
拿《敏》中P118中Button和Lamp对象的例子来说,作者举了一个不成熟的设计,如下:
public class Button{
private Lamp itsLamp;
public void poll(){
if(/* some condition*/){
itsLamp.turnOn();
}
}
}
作者说,这个例子背后的抽象是检测用户的开/关指令并将指令传给目标对象,而检测用户指令的机制是无关紧要的,目标对象同样也是无关紧要的。我按照作者的分析写了一段程序,如下所示:
public interface SwitchableDevice {
public void turnOn();
public void turnOff();
}
public class Lamp implements SwitchableDevice{
public void turnOn(){
//do something
}
public void turnOff(){
//do something
}
}
public class Button {
public void poll(SwitchableDevice device){
device.turnOff();
}
public void push(SwitchableDevice device){
device.turnOn();
}
}
这样子,Button类就可以控制所有实现了SwitchableDevice接口的对象,而lamp也变成了依赖于SwitchableDevice接口,而不必在乎谁来控制它。
5. 接口隔离原则
不应该强迫客户依赖于他们不用的方法。
使用多个专门的接口比使用单一的总接口要好,一个类对另外一个类的依赖性应当建立在最小的接口上。