Design Principle-Interface Isolation Principle

Definition: The client should not rely on interfaces it does not need; the dependency of one class on another should be based on the smallest interfaces.

The problem arises: Class A depends on Class B through Interface I, Class C depends on Class D through Interface I. If Interface I is not the smallest interface for Class A and Class B, Class B and Class D must implement the methods they do not need.

Solution: Divide the bloated interface I into several separate interfaces. Class A and C establish dependencies with the interfaces they need, respectively. That is to say, the principle of interface isolation is adopted.

An example is given to illustrate the principle of interface isolation:

(Figure 1: Design that does not follow the principle of interface isolation)

This graph means that class A depends on method 1, method 2, method 3 in interface I, and class B implements class A dependency. Class C relies on methods 1, 4 and 5 in interface I. Class D is the realization of class C dependency. For Class B and Class D, although they all have unnecessary methods (that is, the red font marking method in the figure), but because of the implementation of interface I, these unnecessary methods must also be implemented. Unfamiliar with class diagrams can be understood by referring to program code, which is as follows:

  1. interface I {  
  2.     public void method1();  
  3.     public void method2();  
  4.     public void method3();  
  5.     public void method4();  
  6.     public void method5();  
  7. }  
  8.   
  9. class A{  
  10.     public void depend1(I i){  
  11.         i.method1();  
  12.     }  
  13.     public void depend2(I i){  
  14.         i.method2();  
  15.     }  
  16.     public void depend3(I i){  
  17.         i.method3();  
  18.     }  
  19. }  
  20.   
  21. class B implements I{  
  22.     public void method1() {  
  23.         System.out.println("class B Implementation interface I Method 1");  
  24.     }  
  25.     public void method2() {  
  26.         System.out.println("class B Implementation interface I Method 2");  
  27.     }  
  28.     public void method3() {  
  29.         System.out.println("class B Implementation interface I Method 3");  
  30.     }  
  31.     //For class B, method4 and method5 are not necessary, but because there are two methods in interface A,  
  32.     //So in the process of implementation, even if the two methods are empty, the two ineffective methods should be implemented.  
  33.     public void method4() {}  
  34.     public void method5() {}  
  35. }  
  36.   
  37. class C{  
  38.     public void depend1(I i){  
  39.         i.method1();  
  40.     }  
  41.     public void depend2(I i){  
  42.         i.method4();  
  43.     }  
  44.     public void depend3(I i){  
  45.         i.method5();  
  46.     }  
  47. }  
  48.   
  49. class D implements I{  
  50.     public void method1() {  
  51.         System.out.println("class D Implementation interface I Method 1");  
  52.     }  
  53.     //For class D, method2 and method3 are not necessary, but because there are two methods in interface A,  
  54.     //So in the process of implementation, even if the two methods are empty, the two ineffective methods should be implemented.  
  55.     public void method2() {}  
  56.     public void method3() {}  
  57.   
  58.     public void method4() {  
  59.         System.out.println("class D Implementation interface I Method 4");  
  60.     }  
  61.     public void method5() {  
  62.         System.out.println("class D Implementation interface I Method 5");  
  63.     }  
  64. }  
  65.   
  66. public class Client{  
  67.     public static void main(String[] args){  
  68.         A a = new A();  
  69.         a.depend1(new B());  
  70.         a.depend2(new B());  
  71.         a.depend3(new B());  
  72.           
  73.         C c = new C();  
  74.         c.depend1(new D());  
  75.         c.depend2(new D());  
  76.         c.depend3(new D());  
  77.     }  
  78. }  

As you can see, if the interface is too bulky, it is obviously not a good design to implement methods in the implementation class as long as the methods in the interface appear, regardless of their usefulness to the classes that depend on it. If this design is modified to conform to the principle of interface isolation, interface I must be split. Here we divide the original interface I into three interfaces, and the design after splitting is shown in Figure 2.


(Figure 2: Design following the principle of interface isolation)

Paste out the code of the program as usual for friends who are not familiar with class diagrams.

  1. interface I1 {  
  2.     public void method1();  
  3. }  
  4.   
  5. interface I2 {  
  6.     public void method2();  
  7.     public void method3();  
  8. }  
  9.   
  10. interface I3 {  
  11.     public void method4();  
  12.     public void method5();  
  13. }  
  14.   
  15. class A{  
  16.     public void depend1(I1 i){  
  17.         i.method1();  
  18.     }  
  19.     public void depend2(I2 i){  
  20.         i.method2();  
  21.     }  
  22.     public void depend3(I2 i){  
  23.         i.method3();  
  24.     }  
  25. }  
  26.   
  27. class B implements I1, I2{  
  28.     public void method1() {  
  29.         System.out.println("class B Implementation interface I1 Method 1");  
  30.     }  
  31.     public void method2() {  
  32.         System.out.println("class B Implementation interface I2 Method 2");  
  33.     }  
  34.     public void method3() {  
  35.         System.out.println("class B Implementation interface I2 Method 3");  
  36.     }  
  37. }  
  38.   
  39. class C{  
  40.     public void depend1(I1 i){  
  41.         i.method1();  
  42.     }  
  43.     public void depend2(I3 i){  
  44.         i.method4();  
  45.     }  
  46.     public void depend3(I3 i){  
  47.         i.method5();  
  48.     }  
  49. }  
  50.   
  51. class D implements I1, I3{  
  52.     public void method1() {  
  53.         System.out.println("class D Implementation interface I1 Method 1");  
  54.     }  
  55.     public void method4() {  
  56.         System.out.println("class D Implementation interface I3 Method 4");  
  57.     }  
  58.     public void method5() {  
  59.         System.out.println("class D Implementation interface I3 Method 5");  
  60.     }  
  61. }  

The meaning of the principle of interface isolation is: to establish a single interface, not to build a huge and bulky interface, to refine the interface as much as possible, and to minimize the number of methods in the interface. That is to say, we need to build a dedicated interface for each class, rather than trying to build a very large interface for all classes that depend on it to call. In this example, the principle of interface isolation is used to change a huge interface to three dedicated interfaces. In programming, it is more flexible to rely on several specialized interfaces than on a comprehensive one. Interface is a contract for external design. By defining multiple interfaces separately, it can prevent the spread of external changes and improve the flexibility and maintainability of the system.

At this point, many people will feel that the principle of interface isolation is very similar to the previous principle of single responsibility, but it is not. First, the principle of single responsibility originally focused on responsibility, while the principle of interface isolation focused on isolation of interface dependency. Secondly, the principle of single responsibility is mainly constrained class, followed by interface and method, which aims at the realization and details of the program; while the principle of interface isolation mainly constrains the interface, mainly for abstraction, for the construction of the overall framework of the program.

When using the principle of interface isolation to restrict interfaces, the following points should be paid attention to:

  • The interface is as small as possible, but with a limit. It is a fact that refinement of interfaces can improve the flexibility of programming, but if it is too small, it will result in too many interfaces and complicate the design. So we must be moderate.
  • Customizing services for classes that depend on interfaces exposes only the methods it needs for the invoked class, and hides the methods it does not need. Only by focusing on providing customized services for a module can minimal dependencies be established.
  • Improve cohesion and reduce external interaction. Make the interface do the most in the least way.

Using the principle of interface isolation, we must be moderate, too large or too small interface design is not good. When designing interfaces, we can accurately practice this principle only if we spend more time thinking and planning.

Keywords: Programming

Added by Lefu on Wed, 19 Jun 2019 22:34:23 +0300