接口隔离原则(Interface Segregation Principle,ISP)要求程序员尽量将臃肿庞大的接口拆分成更小的和更具体的接口,让接口中只包含客户感兴趣的方法。
与上一篇介绍的单一职责原则类似,接口隔离原则同样是为了提高类的内聚性、降低它们之间的耦合性,都是面向对象三个基本特征中的“封装”思想的体现。
但两者也存在不同之处:
单一职责 | 接口隔离 | |
作用目标 | 类 | 接口 |
范围级别 | 实现细节 | 整体框架 |
侧重方面 | 职责划分 | 接口依赖 |
这里重点说一下“接口依赖”与“接口实现”的区别:
依赖(Dependency)关系是一种使用关系,它是对象之间耦合度最弱的一种关联方式,是临时性的关联。
在代码中,某个类的方法通过局部变量、方法的参数或者对静态方法的调用来访问另一个类(被依赖类)中的某些方法来完成一些职责。
图形表示:依赖关系使用虚线箭头表示,使用类指向被依赖的类。(下图左侧的线)
实现(Realization)关系是接口与实现类之间的关系。在这种关系中,类实现了接口,类中的操作实现了接口中所声明的所有的抽象操作。
图形表示:实现关系使用带空心三角箭头的虚线来表示,箭头从实现类指向接口。(下图右侧的线)
如上面的UML类图所示:
下面以代码的方式说明两者的区别。
1 package asen.yang; 2 public interface IAction { 3 public void eat(); 4 5 public void sleep(); 6 7 public void beatDD(); 8 } 9 10 public class CommonAction implements IAction { 11 12 @Override 13 public void eat() { 14 System.out.println("吃饭"); 15 } 16 17 @Override 18 public void sleep() { 19 System.out.println("睡觉"); 20 } 21 22 @Override 23 public void beatDD() { 24 System.out.println("打豆豆"); 25 } 26 } 27 28 public class People { 29 private String Name; 30 31 public People(String Name) { 32 this.Name = Name; 33 } 34 35 protected void Action() { 36 IAction action = new CommonAction(); 37 System.out.println("我是" + Name); 38 System.out.println("我的爱好有:"); 39 action.eat(); 40 action.sleep(); 41 action.beatDD(); 42 } 43 } 44 45 public class ISP_Demo { 46 public static void main(String[] args) { 47 People p = new People("小明"); 48 p.Action(); 49 } 50 }
Action类"实现"了IAction接口,因此要实现接口中所声明的所有方法。
而People类“依赖”IAction接口,在People类的Action()方法中,使用了IAction类型的变量action。
本原则所侧重的就是第二种形式的接口依赖关系。
假如除了人这个类别之外,还有一个狗类,而狗并不会打豆豆,只会吃饭睡觉。依照本原则,就应该将IAction拆分。
UML类图如下:
对应的代码可以重构为:
1 package asen.yang; 2 public interface ILowAction { 3 public void eat(); 4 public void sleep(); 5 } 6 7 public interface IHighAction{ 8 public void beatDD(); 9 } 10 11 public class LowAction implements ILowAction { 12 @Override 13 public void eat() { 14 System.out.println("吃饭"); 15 } 16 17 @Override 18 public void sleep() { 19 System.out.println("睡觉"); 20 } 21 } 22 23 public class HighAction implements IHighAction{ 24 25 @Override 26 public void beatDD() { 27 System.out.println("打豆豆"); 28 } 29 } 30 31 public class People { 32 private String Name; 33 34 public People(String Name) { 35 this.Name = Name; 36 } 37 38 public void Action() { 39 ILowAction lowaction = new LowAction(); 40 System.out.println("我是" + Name); 41 System.out.println("我的低级爱好有:"); 42 lowaction.eat(); 43 lowaction.sleep(); 44 45 IHighAction highaction = new HighAction(); 46 System.out.println("我的高级爱好有:"); 47 highaction.beatDD(); 48 } 49 } 50 51 public class Dog { 52 private String Name; 53 54 public Dog(String Name) { 55 this.Name = Name; 56 } 57 58 public void Action() { 59 ILowAction lowaction = new LowAction(); 60 System.out.println("我是" + Name); 61 System.out.println("我的爱好有:"); 62 lowaction.eat(); 63 lowaction.sleep(); 64 } 65 } 66 67 public class ISP_Demo { 68 public static void main(String[] args) { 69 People p = new People("小明"); 70 p.Action(); 71 72 Dog d = new Dog("汪汪"); 73 d.Action(); 74 } 75 }
将"吃饭"、"睡觉"这两种人与狗都有的共性的行为,单独封装在一个接口中。而将只有人具有的"打豆豆"这个行为,封装在单独的接口中。
这就是接口隔离原则的最直接体现。