在本讲,我将为大家介绍软件设计原则里面的第四个原则,即接口隔离原则。
概述
接口隔离原则是指客户端不应该被迫依赖于它不使用的方法,一个类对另一个类的依赖应该建立在最小的接口上面。
这句话可能不是很好理解,所以下面我会画一张图来解释一下。先看的是前半段话,客户端不应该被迫依赖于它不使用的方法,这是什么意思呢?
从上图中,相信大家能够更好地理解前半段话的内容,所以,在上述这种情景下,我们是不能使用继承关系的。那么,现在我们应该如何对其进行改进呢?其实,在接口隔离原则概述的后半段话中就已经说了,即一个类对另一个类的依赖应该建立在最小的接口上面。改进之后,就变成下图所示的这样了。
通过上面两张图的解释,相信大家对于接口隔离原则的概念有了一个更深入的认识。
接下来,我们就通过一个例子来更深入的去理解一下接口隔离原则。
案例
这个例子就是安全门案例。
案例分析
我们现在需要创建一个美美侠 品牌的安全门,该安全门具有防火、防水、防盗的功能。
要想做到这一点的话,咱们首先得设计出类图来。那我们应该如何去设计呢?可以将防火、防水、防盗等功能提取到一个接口里面,形成一套规范,所以,设计出来的类图应该如下所示。
如果你想要去设计安全门的话,那么你只需要去实现SafetyDoor接口,并重写它里面的所有的抽象方法就可以了。
接下来,我们便来通过代码实现以上安全门案例。
案例实现
打开咱们的maven工程,然后在com.meimeixia.principles包下创建一个子包,即demo4,接着在com.meimeixia.principles.demo4包下再创建一个子包,即before,我们首次是在该包下来存放咱们编写的代码的。接下来,我们就要正式开始编写代码来实现以上案例了。
首先,定义一个SafetyDoor接口,即安全门接口。
package com.meimeixia.principles.demo4.before;
public interface SafetyDoor {
void antiTheft();
void fireProof();
void waterProof();
}
然后,定义以上接口的一个实现类,例如美美侠 安全门。
package com.meimeixia.principles.demo4.before;
public class MeimeixiaSafetyDoor implements SafetyDoor {
@Override
public void antiTheft() {
System.out.println("防盗");
}
@Override
public void fireProof() {
System.out.println("防火");
}
@Override
public void waterProof() {
System.out.println("防水");
}
}
最后,我们来编写一个测试类用作测试,不妨取名为Client。
package com.meimeixia.principles.demo4.before;
public class Client {
public static void main(String[] args) {
MeimeixiaSafetyDoor door = new MeimeixiaSafetyDoor();
door.antiTheft();
door.fireProof();
door.waterProof();
}
}
以上测试类编写好之后,不妨来运行一下,如下图所示,可以看到,咱们设计的美美侠 安全门确实具有了防盗、防火、防水的功能。
对于以上设计,你觉得存不存在什么问题啊?如果我们现在再提一个需求,即还想再创建一个阿昀 品牌的安全门,而该安全门只具有防盗、防火功能,不具有防水功能,那么难道我们需要再去定义一个类,让它去实现SafetyDoor接口吗?很显然不能,因为如果让新建的类再去实现SafetyDoor接口的话,那么就意味着该类要被迫依赖于它不使用的方法,即防水的方法,这也就违背了接口隔离原则。
那么我们又该如何进行修改呢?下面就会说到。
案例改进
虽然我们实现了以上安全门案例,但是我们也看到该案例所存在的问题,即违背了接口隔离原则。因此,我们就得需要对其进行改进了。那如何进行改进呢?
首先,咱们得按照接口隔离原则来重新设计出以下类图。
从以上类图中可以看到,我们是将安全门的接口给它拆分成了不同的接口,分别是防盗接口、防火接口、防水接口。现在,如果我们想要去创建一个美美侠 品牌的安全门的话,那么只需要让其分别去实现这三个接口就可以了。要是后期我们还想要再创建一个阿昀 品牌的安全门的话,而该安全门只具有防盗、防火功能,那么我们只须让其去实现防盗、防火这两个接口就可以了。
分析完了之后,下面我们来看一下代码的具体实现。
首先,在com.meimeixia.principles.demo4包下再创建一个子包,即after,该包下存放的就是改进后的案例的代码。
然后,创建防盗接口。
package com.meimeixia.principles.demo4.after;
public interface AntiTheft {
void antiTheft();
}
接着,创建防火接口。
package com.meimeixia.principles.demo4.after;
public interface Fireproof {
void fireproof();
}
紧接着,创建防水接口。
package com.meimeixia.principles.demo4.after;
public interface Waterproof {
void waterproof();
}
以上三个接口定义完毕之后,接下来,我们来定义美美侠 品牌的安全门类,并让其去实现以上三个接口。
package com.meimeixia.principles.demo4.after;
public class MeiMeiXiaSafetyDoor implements AntiTheft, Fireproof, Waterproof {
@Override
public void antiTheft() {
System.out.println("防盗");
}
@Override
public void fireproof() {
System.out.println("防火");
}
@Override
public void waterproof() {
System.out.println("防水");
}
}
最后,来编写一个测试类进行测试。
package com.meimeixia.principles.demo4.after;
public class Client {
public static void main(String[] args) {
MeiMeiXiaSafetyDoor door = new MeiMeiXiaSafetyDoor();
door.antiTheft();
door.fireproof();
door.waterproof();
}
}
以上测试类编写好之后,不妨来运行一下,如下图所示,可以看到,咱们设计的美美侠 安全门确实具有了防盗、防火、防水的功能。
这时,应该是解决了之前案例所存在的问题,为了验证这一点,我们在这儿再去定义一个阿昀 品牌的安全门类,而且该类只具有防盗和防火功能,因此我们得让该类去实现防盗、防火这两个接口。
package com.meimeixia.principles.demo4.after;
public class AyunSafetyDoor implements AntiTheft, Fireproof {
@Override
public void antiTheft() {
System.out.println("防盗");
}
@Override
public void fireproof() {
System.out.println("防火");
}
}
以上类定义完毕之后,我们再在Client测试类中编写如下代码进行测试。
package com.meimeixia.principles.demo4.after;
public class Client {
public static void main(String[] args) {
MeiMeiXiaSafetyDoor door = new MeiMeiXiaSafetyDoor();
door.antiTheft();
door.fireproof();
door.waterproof();
System.out.println("===================");
AyunSafetyDoor door1 = new AyunSafetyDoor();
door1.antiTheft();
door1.fireproof();
}
}
这时,不妨来运行一下以上测试类,如下图所示,可以看到,咱们设计的阿昀 安全门确实是只具有防盗、防火这俩功能。
至此,安全门案例我们就改进完毕了,现在更好地符合了接口隔离原则。
|