概述
简介
前面我们已经介绍了
- SRP ,单一职责原则
- OCP,开闭原则
- LSP,里式替换原则
今天来讲解接口隔离原则。
接口是Java 编程语言的核心功能之一,在企业应用开发中被广泛应用来抽象业务和多接口的实现能力。从写代码的角度,写一个接口是简单的,你可以用 interface
关键字创建一个接口并在接口里声明一些方法,其他的类可以通过 implements
关键字来实现接口定义的方法。作为一个 java 使用者,你肯定写过很多接口,但是有没有想过这样一个问题:之前写的接口是否是合理的,有没有好的设计原则可以指导我们编写出良好的接口? 下面详解的 接口隔离原则
可以回答这个问题。
接口隔离原则(Interface Segregation Principle,简称ISP
)代表SOLID
原则中的I
,SOLID
原则是面向对象编程中设计原则,遵循这些原则可使我们的代码易读、易维护、易升级、易修改。接口隔离原则是 Robert C.Martin 在2002年出的一本书 《Agile Software Development: Principles, Patterns and Practices》 里提出的,原则的描述是 Clients should not be forced to depend upon interfaces that they do not use
,直译为: 客户端不应该被强迫依赖它不需要的接口。其中客户端是指实现接口的类。
接口隔离原则告诉我们接口不应包含实现类不需要的方法,否则,这类接口我们称之为胖接口
,实现胖接口的类要为那些不需要的方法提供空实现,除此之外,当接口发生变化时实现类也会被迫修改,尤其是那些使用不到的方法签名发生变化。接口隔离原则主张把胖接口分离成高内聚的小接口,这些小接口被称为角色接口
。每个角色接口只包含与他紧密相关的方法,从而,实现类只实现与它相关联的接口。
违反接口隔离原则的例子
有一个需求,开发一个生产不同类型的玩具的应用,每个玩具会有价格和颜色的基本属性,如汽车和火车有移动的行为,但另一些玩具,如飞机有移动和飞的行为。因此,我们定义一个接口
public interface Toy {
void setPrice(double price);
void setColor(String color);
void move();
void fly();
}
如果玩具是飞机,它能实现这个接口的所有方法,如过是房子,只能实现部分方法,代码如下:
public class ToyHouse implements Toy {
double price;
String color;
@Override
public void setPrice(double price) {
this.price = price;
}
@Override
public void setColor(String color) {
this.color=color;
}
@Override
public void move(){}
@Override
public void fly(){}
}
如代码所示,类ToyHouse
提供了方法 move
、fly
的空实现。此时接口Toy
的设计违反了ISP,ToyHouse
的实现会影响代码的可读性和是维护代码的工程师困惑:为啥这些方法只提供了空实现呢。
违反ISP也可能导致违反开闭原则,继续以上的例子来讲,如果为Toy
添加一个 walk()
方法,那么实现Toy
的类都将被修改,违反了对修改关闭的原则。
遵循接口隔离原则
为了满足ISP,你可以把胖接口Toy
分离成三个小接口: Toy
,Movable
,Flyable
, 把方法move
移到接口Movable
,方法fly()
移到接口Flyable
,让实现类按需实现相应的接口。
public interface Toy {
void setPrice(double price);
void setColor(String color);
}
public interface Movable {
void move();
}
public interface Flyable {
void fly();
}
public class ToyHouse implements Toy {
double price;
String color;
@Override
public void setPrice(double price) {
this.price = price;
}
@Override
public void setColor(String color) {
this.color=color;
}
@Override
public String toString(){
return "ToyHouse: Toy house- Price: "+price+" Color: "+color;
}
}
public class ToyCar implements Toy, Movable {
double price;
String color;
@Override
public void setPrice(double price) {
this.price = price;
}
@Override
public void setColor(String color) {
this.color=color;
}
@Override
public void move(){
System.out.println("ToyCar: Start moving car.");
}
@Override
public String toString(){
return "ToyCar: Moveable Toy car- Price: "+price+" Color: "+color;
}
}
public class ToyPlane implements Toy, Movable, Flyable {
double price;
String color;
@Override
public void setPrice(double price) {
this.price = price;
}
@Override
public void setColor(String color) {
this.color=color;
}
@Override
public void move(){
System.out.println("ToyPlane: Start moving plane.");
}
@Override
public void fly(){
System.out.println("ToyPlane: Start flying plane.");
}
@Override
public String toString(){
return "ToyPlane: Moveable and flyable toy plane- Price: "+price+" Color: "+color;
}
}
public class ToyBuilder {
public static ToyHouse buildToyHouse(){
ToyHouse toyHouse=new ToyHouse();
toyHouse.setPrice(15.00);
toyHouse.setColor("green");
return toyHouse;
}
public static ToyCar buildToyCar(){
ToyCar toyCar=new ToyCar();
toyCar.setPrice(25.00);
toyCar.setColor("red");
toyCar.move();
return toyCar;
}
public static ToyPlane buildToyPlane(){
ToyPlane toyPlane=new ToyPlane();
toyPlane.setPrice(125.00);
toyPlane.setColor("white");
toyPlane.move();
toyPlane.fly();
return toyPlane;
}
}
public class ToyBuilderTest {
@Test
public void testBuildToyHouse() throws Exception {
ToyHouse toyHouse=ToyBuilder.buildToyHouse();
System.out.println(toyHouse);
}
@Test
public void testBuildToyCar() throws Exception {
ToyCar toyCar=ToyBuilder.buildToyCar();;
System.out.println(toyCar);
}
@Test
public void testBuildToyPlane() throws Exception {
ToyPlane toyPlane=ToyBuilder.buildToyPlane();
System.out.println(toyPlane);
}
}
总结
接口隔离原则和单一职责原则有同样的目的:确保设计出小的、聚焦的、高内聚的软件组件。两者不同的是,单一职责原则关心的是类,接口隔离原则关心的是接口。接口隔离原则比较容易理解和使用。但是,也要当心防止接口被分割的过细,因此,需要思考接口的职责范围,可以根据角色划分接口。
除了我们上面讲解的java 编程语言的接口外,我们常讲的接口还有两类
- 一类是一组接口集合,常见是微服务的接口和类库的接口。
- 另一类是大个 API 接口或者函数,调用者只需要函数中的部分功能,我们需要把大而全的函数拆分成粒度更细的多个函数,让调用者只依赖它需要的那个细粒度的函数。
以上两类接口,从更广泛的角度理解,ISP 也同样适用,可以指导我们在高层次上进行设计。
最后
以上就是留胡子斑马为你收集整理的SOLID原则-接口隔离原则的全部内容,希望文章能够帮你解决SOLID原则-接口隔离原则所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复