六大原则体现很多编程的底层逻辑:高内聚、低耦合、面向对象编程、面向接口编程、面向抽象编程,最终实现可读、可复用、可维护性。
设计模式的六大原则有:
本文介绍 SOLID 中的第四个原则:接口隔离原则。它对应 SOLID 中的英文字母“I”。
接口隔离原则的英文翻译是“ Interface Segregation Principle”,缩写为 ISP。
Robert Martin 在 SOLID 原则中是这样定义它的:“Clients should not be forced to depend upon interfaces that they do not use。”直译成中文的话就是:客户端不应该被强迫依赖它不需要的接口。
其中的“客户端”,可以理解为接口的调用者或者使用者。
接口隔离的原则的目的是系统解开耦合,从而容易重构。
接口尽量小,功能尽量单一,说白了就是接口粒度要细。
“接口”这个名词可以用在很多场合中。生活中我们可以用它来指插座接口等。在软件开发中,我们既可以把它看作一组抽象的约定,也可以具体指系统与系统之间的 API 接口,还可以特指面向对象编程语言中的接口等。
理解接口隔离原则的关键,就是理解其中的“接口”二字。在这条原则中,我们可以把“接口”理解为下面三种东西:
如果把“接口”理解为一组接口集合,可以是某个微服务的接口,也可以是某个类库的接口等。如果部分接口只被部分调用者使用,我们就需要将这部分接口隔离出来,单独给这部分调用者使用,而不强迫其他调用者也依赖这部分不会被用到的接口。
如果把“接口”理解为单个 API 接口或函数,部分调用者只需要函数中的部分功能,那我们就需要把函数拆分成粒度更细的多个函数,让调用者只依赖它需要的那个细粒度函数。
如果把“接口”理解为 OOP 中的接口,也可以理解为面向对象编程语言中的接口语法。那接口的设计要尽量单一,不要让接口的实现类和调用者,依赖不需要的接口函数。
在具体应用该原则时,可以参考下面几个规则衡量:
分享一张来自 java硕哥 整理的思维导图:
单一职责原则针对的是模块、类、接口的设计。
接口隔离原则相对于单一职责原则,一方面更侧重于接口的设计,另一方面它的思考角度也是不同的。
接口隔离原则提供了一种判断接口的职责是否单一的标准:通过调用者如何使用接口来间接地判定。
如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一。
实现一个音乐播放器, 定义一个接口:
interface IMusicPlayer {
//开始
void start();
//停止
void stop();
//暂停
void pause();
//复原
void resume();
//获取歌曲时长
String getSongLength();
}
这里满足了单一职责原则,却不满足接口隔离。
假如我们现在有个歌曲展示器 SongDisplayer,需要展示歌曲时长,那么我们也应该有个 getSongLength() 函数,我们直接实现 IMusicPlayer接口吗,实现这个接口就必须实现里面的start()等方法,但是这些方法肯定不是我需要的,也不是我应该有的,这就是问题,因为接口不够小,不干净,不纯粹,明显违背了接口隔离原则,我们就可以对接口进行拆分:
//音乐播放器就仅限于对播放的控制
interface IMusicPlayer {
//开始
void start();
//停止
void stop();
//暂停
void pause();
//复原
void resume();
...
}
//歌曲展示器就仅限于对歌曲信息的展示
interface ISongDisplayer {
//获取歌曲时长
String getSongLength();
//获取歌曲名字
String getSongName();
...
}
当我们实现播放器时 可以同时实现这两个接口即可,只需要展示歌曲信息的话,只需要单独实现 ISongDisplayer
即可。
public class MyPlayer implements IMusicPlayer,ISongDisplayer{
//……
}
这样实现便更利于维护,也符合我们的接口隔离原则。
接口要尽量小,尽量单一,无关的接口不要冗余。粒度小,更耦合,更灵活,不会伤筋动骨。
参考:
《设计模式之美》
《重学 Java 设计模式》
《Android 源码设计模式解析与实战》