接口隔离原则(Interface Segregation Principle ISP):客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上
定义:
1.使用多个专门的接口比使用单一的总接口要好
2.一个类对另外一个类的依赖性应当是建立在最小的接口上的
3.一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染
4.不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构
问题由来:类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法。
解决方案:将大接口I拆分为独立的几个小接口,类A和类C分别与他们需要的接口建立依赖关系。
举例说明:继续以上一章打印机墨盒为例:
上一次我们为墨盒设计接口:
接口 Box:
public interface Box {
public abstract void doPrint();
}
黑色墨盒 BlackCartridge:
public class BlackCartridge {
public void doPrint (){
System.out.println("黑色墨盒执行喷墨打印");
}
}
彩色墨盒 ColorCartridge:
public class ColorCartridge implements Box{
public void doPrint (){
System.out.println("彩色墨盒执行喷墨打印");
}
}
打印机Printer :
public class Printer {
public void print(Box box){
box. doPrint ();
}
}
这是上一章的内容,为了符合墨盒的功能,我们考虑到喷墨墨盒应该有添加墨水的功能,激光打印头应该能更换,硒鼓可以加粉,同时添加了不同类型的墨盒实现,因此我们设计了如下接口:
接口BOX:
public interface Box {
public abstract void doPrint();
public abstract void addInk();
public abstract void addToner();
public abstract void replaceLaser();}
黑色墨盒BlackCartridge:
public class BlackCartridge implements Box {
public void doPrint() {
System.out.println("黑色墨盒开始打印");
}@Override
public void addInk() {
System.out.println("添加墨水");
}@Override
public void addToner() { }@Override
public void replaceLaser() { }}
彩色墨盒ColorCartridge:
public class ColorCartridge implements Box {
@Override
public void doPrint() {
System.out.println("彩色墨盒开始打印");
}@Override
public void addInk() {
System.out.println("添加墨水");
}@Override
public void addToner() { }@Override
public void replaceLaser() { }}
硒鼓DrumUnit:
public class DrumUnit implements Box {
@Override
public void doPrint() {
System.out.println("硒鼓组开始打印");
}@Override
public void addInk() { }@Override
public void addToner() {
System.out.println("添加墨粉");
}@Override
public void replaceLaser() { }}
激光头Laser:
public class Laser implements Box {
@Override
public void doPrint() {
System.out.println("激光打印");
}@Override
public void addInk() { }@Override
public void addToner() { }@Override
public void replaceLaser() {
System.out.println("激光打印");
}}
事实是,墨水墨盒并不需要加墨粉和更换激光头,激光头也不需要加墨水。然而由于接口设计得过于臃肿,无论对实现它的类有没有用处,都必须实现接口里的所有方法,这样就必须在墨水型墨盒里添加上加墨粉和更换激光头的操作,也必须让激光能添加墨水,这样奇怪的设计肯定是不符合逻辑的,不同类型的墨盒都增加了不必要的操作(每个实现类中加粗斜体的方法),每个实现类互相互相污染
使用接口隔离原则重构代码
使用单一的小接口拆分大接口,让每个小接口满足当前角色需求
接口BOX:
public interface Box {
public abstract void doPrint();
}
接口INKBOX:
public interface InkBox extends Box {
public abstract void addInk;
}
接口UNITBOX:
public interface UnitBox extends Box {
public abstract void addToner;
}
接口LASERBOX:
public interface LaserBox extends Box {
public abstract void replaceToner;
}
让每个实现类实现自己角色的小接口
黑色墨盒BlackCartridge:
public class BlackCartridge implements InkBox {
@Override
public void doPrint() {
System.out.println("黑色墨盒开始打印");
}@Override
public void addInk() {
System.out.println("添加墨水");
}}
彩色墨盒ColorCartridge:
public class ColorCartridge implements InkBox {
@Override
public void doPrint() {
System.out.println("彩色墨盒开始打印");
}@Override
public void addInk() {
System.out.println("添加墨水");
}}
硒鼓DrumUnit:
public class DrumUnit implements UnitBox {
@Override
public void doPrint() {
System.out.println("硒鼓组开始打印");
}@Override
public void addToner() {
System.out.println("添加墨粉");
}}
激光头Laser:
public class Laser implements LaserBox {
@Override
public void doPrint() {
System.out.println("激光打印");
}@Override
public void replaceLaser() {
System.out.println("激光打印");
}}
这样可以最大程度的降低角色之间的污染
接口隔离原则就是建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。为各个角色建立专用的接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。本例中,将一个庞大的公共接口变更为几个专用的接口所采用的就是接口隔离原则。在程序设计中,依赖几个专用的接口要比依赖一个综合的接口更灵活。接口是设计时对外部设定的“契约”,通过分散定义多个接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
接口隔离原则和单一职责原则多少有相似之处,而不同之处在于,单一职责原则主要是约束类,它针对的是程序中的实现和细节,注重职责;接口隔离原则主要约束接口,针对程序整体和抽象,注重对接口依赖的隔离。
采用接口隔离原则对接口进行约束时,要注意以下几点:
对接口进行细化可以提高程序设计灵活性但要防止接口数量过多,使设计复杂化。
为角色定制服务,只暴露给调用的类它需要的方法,只专注为一个模块提供定制服务。
提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
蜗牛学院,只为成就更好的你!
你!敢不敢!用你三个月的时间,换你不一样的未来!
赶快关注蜗牛学院官方微信,了解更多信息吧!