接口隔离原则的英文翻译是“ Interface Segregation Principle”,缩写为 ISP,英文描述:
clients should not be forced to depend upon interfaces that they do not use。
翻译过来就是:客户端不应该被强迫依赖它不需要的接口。其中的“客户端”,可以理解为接口的调用者或者使用者。
下面结合代码进行理解。
假如项目中用到了3中配置RedisConfig
,MysqlConfig
,KafkaConfig
public class RedisConfig {
private ConfigSource configSource;
private String address;
private int timeout;
private int maxTotal;
public RedisConfig(ConfigSource configSource) {
this.configSource = configSource;
}
// 省略其他方法
}
public class KafkaConfig { //...省略... }
public class MysqlConfig { //...省略... }
现有两个新的需求:第一个是,Redis 和 Kafka 配置的信息要热更新,也就是配置中心如果改了配置要能实时同步过来,MySQL的配置不需要;第二个需求是,新增一个接口,能够实时查到MySQL
和 Redis
的配置信息。
第一个需求,我们增加一个定时任务ScheduledUpdater
同步配置信息,第二个需求增加simpleHttpServer
来读取配置信息并展示到页面。新增一个接口Config
:
public interface Config {
void update(); // 用来更新配置信息
String outputInPlainText(); // 用来读取配置信息
}
public class RedisConfig implements Config {
//...需要实现Config的两个接口update/outputInPlainText()
}
public class KafkaConfig implements Config {
//...需要实现Config的两个接口update/outputInPlainText()
}
public class MysqlConfig implements Config {
//...需要实现Config的两个接口update/outputInPlainText()
}
上面的设计,虽然能够实现我们想要的功能,但这里存问题。
KafkaConfig
只需要实现 update()
接口,并不需要实现 output()
相关的接口。同理,MysqlConfig
只需要实现 output()
相关接口,并需要实现 update()
接口。KafkaConfig
跟MysqlConfig
都依赖了他们不需要的接口,影响了代码的可读性跟扩展性。
下面看第二种设计
public interface Updater {
void update();
}
public interface Viewer {
String outputInPlainText();
}
public class RedisConfig implemets Updater, Viewer {
//...省略其他属性和方法...
@Override
public void update() { //... }
@Override
public String outputInPlainText() { //... }
}
public class KafkaConfig implements Updater {
//...省略其他属性和方法...
@Override
public void update() { //... }
}
public class MysqlConfig implements Viewer {
//...省略其他属性和方法...
@Override
public String outputInPlainText() { //... }
}
第二种设计,设计了两个功能单一的接口Updater 和 Viewer
,让有需要的类进行实现,遵从了接口隔离原则,代码更加清晰,更加易于扩展。
单一原则跟接口隔离原则有连续但又有不同,单一职责原则针对的是类、接口,方法的设计,是从功能实现的角度进行思考。接口隔离更加侧重于接口的设计,从类之间的调用关系来思考。