主页传送门: 传送
接口隔离原则,英文名为Interface Segregation Principle,又称ISP原则。
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.
即:客户端不应该依赖它不需要的接口。类间的依赖关系应该建立在最小的接口上。
我们可以把这两个定义概括为一句话:建立单一接口,不要建立臃肿庞大的接口。再通俗一点讲:接口尽量细化,同时接口中的方法尽量少。看到这里大家有可能要疑惑了,这与单一职责原则不是相同的吗?错,接口隔离原则与单一职责的审视角度是不相同的,单一职责要求的是类和接口职责单一,注重的是职责,这是业务逻辑上的划分,而接口隔离原则要求接口的方法尽量少。例如一个接口的职责可能包含10个方法,这10个方法都放在一个接口中,并且提供给多个模块访问,各个模块按照规定的权限来访问,在系统外通过文档约
束“不使用的方法不要访问”,按照单一职责原则是允许的,按照接口隔离原则是不允许的,因为它要求“尽量使用多个专门的接口”。专门的接口指什么?就是指提供给每个模块的都应该是单一接口,提供给几个模块就应该有几个接口,而不是建立一个庞大的臃肿的接口,容纳所有的客户端访问。
我们举一个例子来说明接口隔离原则对我们提出了什么要求。汽车想必大家都见过吧,现在满大街都是,汽车要运行就要加燃料,有烧天然气,氢气,烧油的,烧电的等等,下面我们实现一个加油站工作人员(这里都叫服务员吧,实际加油,加气,充电的场所肯定不在同一个地方,不过未来也可能会整合在一起)给汽车加燃料的场景,给汽车定义三个方法,加油,加气,充电,服务员定义一个加燃料的方法,类图如下:
代码如下:
汽车接口(ICar):
public interface ICar {
void aerate();
void refuel();
void charge();
}
出租车(Taxi):
这里的出租车是烧气的。
public class Taxi implements ICar {
public void aerate() {
System.out.println("我在加气");
}
public void refuel() {
}
public void charge() {
}
}
特斯拉(Tesla):
特斯拉毫无疑问是电车。
public class Tesla implements ICar {
public void aerate() {
}
public void refuel() {
}
public void charge() {
System.out.println("我在充电");
}
}
奔驰车(Benz):
这里奔驰车是烧油的。
public class Benz implements ICar {
public void aerate() {
}
public void refuel() {
System.out.println("我在加油");
}
public void charge() {
}
}
比亚迪汉Dmi(HanDmi):
汉Dmi是油电混动的。
public class HanDmi implements ICar {
public void aerate() {
}
public void refuel() {
System.out.println("我在加油");
}
public void charge() {
System.out.println("我在充电");
}
}
服务员(Waiter):
public class Waiter {
private ICar car;
public Waiter(ICar car) {
this.car = car;
}
public void fueling() {
car.aerate();
car.refuel();
car.charge();
}
}
最后需要一个场景类(Client)把前面的类串起来:
public class Client {
public static void main(String[] args) {
ICar taxi = new Taxi();
Waiter zhangsan = new Waiter(taxi);
zhangsan.fueling();
ICar hanDmi = new HanDmi();
Waiter lisi = new Waiter(hanDmi);
lisi.fueling();
}
}
不知道大家有没有发现上面的汽车(ICar)有很多空实现,这是因为大部分车只使用一到两种燃料,那这种设计方法显然很臃肿,我们尝试修改一下,将汽车接口再细分一下,分为电车,油车,气车(烧气的车简称气车),类图如下:
代码如下:
汽车接口(ICar):
public interface ICar {
}
气车接口(IGasCar):
public interface IGasCar extends ICar{
void aerate();
}
油车接口(IOilCar):
public interface IOilCar extends ICar{
void refuel();
}
电车接口(ITramCar):
public interface ITramCar extends ICar {
void charge();
}
出租车(Taxi):
这里的出租车是烧气的。
public class Taxi implements IGasCar {
public void aerate() {
System.out.println("我在加气");
}
}
特斯拉(Tesla):
特斯拉毫无疑问是电车。
public class Tesla implements ITramCar {
public void charge() {
System.out.println("我在充电");
}
}
奔驰车(Benz):
这里奔驰车是烧油的。
public class Benz implements IOilCar {
public void refuel() {
System.out.println("我在加油");
}
}
比亚迪汉Dmi(HanDmi):
汉Dmi是油电混动的。
public class HanDmi implements IOilCar,ITramCar {
public void refuel() {
System.out.println("我在加油");
}
public void charge() {
System.out.println("我在充电");
}
}
服务员(Waiter):
public class Waiter {
private IGasCar gasCar;
private IOilCar oilCar;
private ITramCar tramCar;
public Waiter(IGasCar gasCar) {
this.gasCar = gasCar;
}
public Waiter(IOilCar oilCar) {
this.oilCar = oilCar;
}
public Waiter(ITramCar tramCar) {
this.tramCar = tramCar;
}
public void aerate() {
gasCar.aerate();
}
public void refuel() {
oilCar.refuel();
}
public void charge() {
tramCar.charge();
}
}
最后需要一个场景类(Client)把前面的类串起来:
public class Client {
public static void main(String[] args) {
IGasCar taxi = new Taxi();
Waiter zhangsan = new Waiter(taxi);
zhangsan.aerate();
ITramCar tesla = new Tesla();
Waiter lisi = new Waiter(tesla);
lisi.charge();
}
}
经过优化之后的设计就符合接口隔离原则,气车,油车,电车互相独立,互不影响,生产汽车的厂商也可以随意按照一种或多种接口标准去实现
接口隔离原则是对接口的定义,同时也是对类的定义,接口和类尽量使用原子接口或原子类来组装。关于原子该怎么划分,在实践中可以根据以下几个规则来衡量:
如果喜欢的话,欢迎 关注 点赞 评论 收藏 一起讨论
你的支持就是我✍️创作的动力!