接口隔离原则
定义
客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
问题由来:
类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类A和类B来说不是最小接口,则类B和类D必须去实现他们不需要的方法。
解决方案:
将臃肿的接口I拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则。
未遵循接口隔离的如下:
遵循接口隔离原则:
举例
互联网公司的各类员工职责划分
违反接口隔离原则
interface IDuty{
void code();
void makeDemand();
void test();
}
static class Programer implements IDuty{
@Override
public void code() {
System.out.println("辛勤的写代码....");
}
@Override
public void makeDemand() {
}
@Override
public void test() {
}
}
static class ProductManager implements IDuty {
@Override
public void code() {
}
@Override
public void makeDemand() {
System.out.println("辛勤的写产品需求....");
}
@Override
public void test() {
}
}
static class Tester implements IDuty{
@Override
public void code() {
}
@Override
public void makeDemand() {
}
@Override
public void test() {
System.out.println("辛勤的测试程序....");
}
}
因为IDuty包含了产品/程序猿/测试的接口,所以所有子类都要实现这些接口,导致了大量的代码冗余,其次也不方便阅读,而且容易让第三方误解(想想,第三方看到你所有员工都能做所有的事情,太扯淡了)。此时应该遵循接口隔离原则,对各个职责进行划分,如下。
interface IProgramer{
void code();
}
interface IProduct{
void makeDemand();
}
interface ITest{
void test();
}
static class Programer implements IProgramer{
@Override
public void code() {
System.out.println("辛勤的写代码....");
}
}
static class ProductManager implements IProduct {
@Override
public void makeDemand() {
System.out.println("辛勤的写产品需求....");
}
}
static class Tester implements ITest{
@Override
public void test() {
System.out.println("辛勤的测试程序....");
}
}
总结
接口隔离原则跟之前的单一职责原则很相似,其实不然。
(1)从原则约束的侧重点来说,接口隔离原则更关注的是接口依赖程度的隔离,更加关注接口的“高内聚”;而单一职责原则更加注重的是接口职责的划分。
(2)从接口的细化程度来说,单一职责原则对接口的划分更加精细,而接口隔离原则注重的是相同功能的接口的隔离。接口隔离里面的最小接口有时可以是多个单一职责的公共接口。
(3)单一职责原则更加偏向对业务的约束,接口隔离原则更加偏向设计架构的约束。这个应该好理解,职责是根据业务功能来划分的,所以单一原则更加偏向业务;而接口隔离更多是为了“高内聚”,偏向架构的设计。
采用接口隔离原则对接口进行约束时,要注意以下几点:
- 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
- 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。