接口隔离原则的定义
首先,我们需要知道什么是接口,接口分两种:
- 实例接口(Object Interface),在Java中声明一个类,然后用new关键字产生一个实例,它是对一个类型的事物的描述,这是一种接口。比如你定义Person这个类,然后使用Person zhangSan= new Person();产生了一个实例,这个实例要遵循的标准就是Person这个类,Person这个类就是zhangSan的接口。疑惑?看不懂?不要紧,那是因为让Java语言浸染的时间太长了,只要知道从这个角度看,Java中的类也是一种接口。
- 类接接口(Class Interface),Java中经常使用interface定义的接口。
主角已经清楚了,那什么是隔离?它有两种定义:
- Clients should not be forced to depend upon interfaces that they don’t use. (客户端不应该依赖它不需要的接口)。
- The dependency of one class to another one should depend on the smallest possible interface. (类间的依赖关系应该建立在最小的接口上。)
新事物的定义一般都比较难理解,晦涩难懂是正常的。我们把这两个定义剖析一下,先说第一种定义:”客户端不应该依赖它不需要的接口“,那依赖是什么?依赖它需要的接口,客户端需要什么接口就提供什么接口,把不需要的接口剔除掉,那就需要对接口进行细化,保证其纯洁性;再看第二种定义:”类间的依赖关系应该建立在最小的接口上“,它要求是最小的接口,也是要求接口细化,接口纯洁,与第一个定义如出一辙,只是一个事物的两种不同描述。
我们把这两个定义概括为一句话:建立单一接口,不要建立臃肿庞大的接口。再通俗点讲:接口尽量细化,同时接口中的方法尽量少。接口隔离原则要求接口中的方法尽量地少。这里要说明的是,隔离不是拆分,单一职责原则体现在拆分上,要求将职责尽量地分离;接口隔离原则则要求接口中的不需要用到的方法尽量地少,至于少到什么程度,在逻辑上是不可度量的,需要结合实际情况考虑。
美女何其多,观点各不同
下面我们建立一个例子来说明接口隔离对我们有什么要求。现在男生对小姑娘的称呼,使用频率最高的应该是”美女“了吧,每个人心目中美女的定义各不相同,但似乎都有一个通用的尺度,或者称为标准,这个标准用面向对象的接口来描述。一名美女需要具备如下:面貌、身材、气质,我们用类图来实现。
定义一个IPrettyGirl接口,声明所有美女都应该有goodLooking、niceFigure、greatTemperament,然后定义了一个抽象类AbstractSearcher,其作用就是搜寻美女并显示信息,并实现其具体类。
代码清单1:IPrettyGirl.java (美女接口)
/**
* 美女类接口
* @author Barudisshu
*/
public interface IPrettyGirl {
/**要有较好的面孔*/
public void goodLooking();
/**要有好身材*/
public void niceFigure();
/**要有气质*/
public void greatTemperament();
}
代码清单2:PrettyGirl.java (美女实现类)
/**
* 美女
*
* @author Barudisshu
*/
public class PrettyGirl implements IPrettyGirl {
//美女都有名字
private String name;
public PrettyGirl(String name) {
this.name = name;
}
@Override
public void goodLooking() {
System.out.println(this.name + "---脸蛋很漂亮!");
}
@Override
public void niceFigure() {
System.out.println(this.name + "---身材非常棒!");
}
@Override
public void greatTemperament() {
System.out.println(this.name + "---气质非常好!");
}
}
代码清单3:AbstractSearcher.java (星探抽象类)
/**
*
* @author Barudisshu
*/
public abstract class AbstractSearcher {
protected IPrettyGirl prettyGirl;
public AbstractSearcher(IPrettyGirl prettyGirl) {
this.prettyGirl = prettyGirl;
}
/**
* 搜索美女,列出美女的信息
*/
public abstract void show();
}
代码清单4:Searcher.java (星探实现类)
/**
*
* @author Barudisshu
*/
public class Searcher extends AbstractSearcher{
public Searcher(IPrettyGirl prettyGirl) {
super(prettyGirl);
}
@Override
public void show() {
System.out.println("------美女的信息如下:------");
//展示面容
super.prettyGirl.goodLooking();
//展示身材
super.prettyGirl.niceFigure();
//展示气质
super.prettyGirl.greatTemperament();
}
}
代码清单5:Client.java (模拟场景)
/**
*
* @author Barudisshu
*/
public class Client {
public static void main(String[] args) {
//定义一个美女
IPrettyGirl yanYan = new PrettyGirl("嫣嫣");
AbstractSearcher searcher = new Searcher(yanYan);
searcher.show();
}
}
星探搜索美女的运行结果如下所示:
星探寻找美女的程序开发完毕了,运行结果也正确了。我们看看这个程序是否是最优的,接口隔离原则的要求是接口的方法应该尽量地少,把不需要的方法尽量隔离。
我们的审美观还在变,美女的定义也在变。比如唐朝的杨贵妃,算是公认的美女了,但是在这里却不符合,为什么?胖啊!但是胖并不影响她入选中国的四大美女,说明当时的审美观与现在存在差异。另一方面,当我们看到一个女孩长得很漂亮,身材也很好,我们觉得她”看“上去是个美女,但当我们发现她粗言秽语、随地仍东西等行为,我们还会认为他是个美女吗?所以,我们需要把握好尺度。
分析到这里,我们发现接口IPrettyGirl接口还是过于庞大,容纳了一些可变因素,我们需要把定义进行分离,我们把美女分割成外在美和内在美的行为,分别定义两个接口IGoodBodyGirl和IGreatTemperamentGirl。
代码清单6:两种类型美女的定义。
/**
*
* @author Barudisshu
*/
public interface IGoodBodyGirl {
/**
* 要有较好的面孔
*/
public void goodLooking();
/**
* 要有好的身材
*/
public void niceFigure();
}
public interface IGreatTemperamentGirl {
/**
* 要有气质
*/
public void greatTemperament();
}
代码清单7:PrettyGirl.java (最标准的美女)
/**
* 标准的美女
*
* @author Barudisshu
*/
public class PrettyGirl implements IGoodBodyGirl, IGreatTemperamentGirl {
//每个美女都有名字
private String name;
public PrettyGirl(String name) {
this.name = name;
}
@Override
public void goodLooking() {
System.out.println(this.name + "---脸蛋很漂亮!");
}
@Override
public void niceFigure() {
System.out.println(this.name + "---身材非常棒!");
}
@Override
public void greatTemperament() {
System.out.println(this.name + "---气质非常好!");
}
}
代码清单8:AbstractSearcher.java (重新定义星探抽象类)
/**
*
* @author Barudisshu
*/
public abstract class AbstractSearcher {
protected IGoodBodyGirl goodBodyGirl;
protected IGreatTemperamentGirl greatTemperamentGirl;
/**
* 外形美的美女
*/
public AbstractSearcher(IGoodBodyGirl goodBodyGirl) {
this.goodBodyGirl = goodBodyGirl;
}
/**
* 气质美的美女
*/
public AbstractSearcher(IGreatTemperamentGirl greatTemperamentGirl) {
this.greatTemperamentGirl = greatTemperamentGirl;
}
/**
* 搜索美女,列出美女的信息
*/
public abstract void show();
}
代码清单10:Searcher.java
/**
*
* @author Barudisshu
*/
public class Searcher extends AbstractSearcher {
public Searcher(IGoodBodyGirl goodBodyGirl) {
super(goodBodyGirl);
}
public Searcher(IGreatTemperamentGirl greatTemperamentGirl) {
super(greatTemperamentGirl);
}
@Override
public void show() {
System.out.println("------美女的信息如下:------");
if (super.goodBodyGirl != null) {
super.goodBodyGirl.goodLooking();
super.goodBodyGirl.niceFigure();
}
if (super.greatTemperamentGirl != null) {
super.greatTemperamentGirl.greatTemperament();
}
}
}
代码清单11:Client.java (模拟场景)
/**
*
* @author Barudisshu
*/
public class Client {
public static void main(String[] args) {
//定义一个气质美女
IGreatTemperamentGirl yanYan = new PrettyGirl("嫣嫣");
AbstractSearcher searcher = new Searcher(yanYan);
searcher.show();
}
}
通过这样的重构后,不管以后是要气质的美女还是要外形的美女,都可以保持接口的稳定。当然,你可能要说,以后可能审美观再发生变化,只要脸蛋好看就是美女,那这个IGoodBody接口还是要修改啊,确实是,但是设计是有限度的,好比如提出行业规范一样,不能无限地考虑未来变更的情况,否则就会陷入设计的泥潭中不能自拔。
保持接口的纯洁性
接口原则是对接口进行规范约束,其包含如下4层含义:
- 接口要尽量小
- 接口要高内聚
- 定制服务
- 接口设计是有限度的
根据接口原则拆分接口时,首先必须满足单一指责原则。