李天炜

设计模式六大原则 - 接口隔离原则

类A通过接口I依赖类B,类C通过接口I依赖类D,如果接口I对于类B和类D来说不是最小接口,则类B和类D必须去实现他们不需要的方法。

原文链接:http://tianweili.github.io/blog/2015/02/10/interface-segregation-principle/

什么是接口隔离原则

接口隔离原则比较简单,有两种定义:

  • 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.(类间的依赖关系应该建立在最小的接口上)

其实上述两种定义说的是同一种意思。客户端不应该依赖它不需要的接口,意思就是说客户端只要依赖它需要的接口,它需要什么接口,就提供什么接口,不提供多余的接口。“类间的依赖关系应该建立在最小的接口上”也表达这一层意思。通俗的讲就是:接口中的方法应该尽量少,不要使接口过于臃肿,不要有很多不相关的逻辑方法。

通过简单的代码还原开篇的问题,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public interface I {
    public void method1();
    public void method2();
    public void method3();
}
public class B implements I{
 
    @Override
    public void method1() {
        System.out.println("类B实现了接口I的方法1");
    }
 
    @Override
    public void method2() {
        System.out.println("类B实现了接口I的方法2");
    }
 
    @Override
    public void method3() {//类B并不需要接口I的方法3功能,但是由于实现接口I,所以不得不实现方法3
        //在这里写一个空方法
    }
}
public class D implements I{
 
    @Override
    public void method2() {
        System.out.println("类D实现了接口I的方法2");
    }
 
    @Override
    public void method3() {
        System.out.println("类D实现了接口I的方法3");
    }
 
    @Override
    public void method1() {//类D并不需要接口I的方法1功能,但是由于实现接口I,所以不得不实现方法1
        //在这里写一个空方法
    }
}
//类A通过接口I依赖类B
public class A {
    public void depend1(I i){
        i.method1();
    }
}
//类C通过接口I依赖类D
public class C {
    public void depend1(I i){
        i.method3();
    }
}
public class Client {
    public static void main(String[] args) {
        A a = new A();
        I i1 = new B();
        a.depend1(i1);
         
        C c = new C();
        I i2 = new D();
        c.depend1(i2);
    }
}

运行结果:

1
2
类B实现了接口I的方法1
类D实现了接口I的方法3

从以上代码可以看出,如果接口过于臃肿,不同业务逻辑的抽象方法都放在一个接口内,则会造成它的实现类必须实现自己并不需要的方法,这种设计方式显然是不妥当的。所以我们要修改上述设计方法,把接口I拆分成3个接口,使得实现类只需要实现自己需要的接口即可。只贴出修改后的接口和实现类的代码,修改代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public interface I1 {
    public void method1();
}
public interface I2 {
    public void method2();
}
public interface I3 {
    public void method3();
}
 
public class B implements I1,I2{
    @Override
    public void method1() {
        System.out.println("类B实现了接口I的方法1");
    }
 
    @Override
    public void method2() {
        System.out.println("类B实现了接口I的方法2");
    }
}
 
public class D implements I2,I3{
    @Override
    public void method2() {
        System.out.println("类D实现了接口I的方法2");
    }
 
    @Override
    public void method3() {
        System.out.println("类D实现了接口I的方法3");
    }
}

与单一职责原则的区别

到了这里,有些人可能觉得接口隔离原则与单一职责原则很相似,其实不然。

第一,单一职责原则注重的是职责;而接口隔离原则注重对接口依赖的隔离。

第二,单一职责原则主要是约束类,其次才是接口和方法,它针对的是程序中的实现和细节;而接口隔离原则主要约束接口,主要针对抽象,针对程序整体框架的构建。

注意事项

原则是前人经验的总结,在软件设计中具有一定的指导作用,但是不能完全照搬这些原则。对于接口隔离原则来说,接口尽量小,但是也要有限度。对接口进行细化可以提高程序设计灵活性是不争的事实,但是如果过小,则会造成接口数量过多,使设计复杂化,所以一定要适度。


作者:李天炜

原文链接:http://tianweili.github.io/blog/2015/02/10/interface-segregation-principle/

转载请注明作者及出处,谢谢。