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

Class A depends on class B through interface I, and class C depends on class D through interface I. If interface I is not the minimum interface for classes A and B, then classes B and D must implement methods they do not need.

Solution: Split bloated interface I into separate interfaces, with classes A and C dependent on the interfaces they need. That is, the interface isolation principle is adopted.

To illustrate the interface isolation principle:

(Figure 1 design without interface isolation)

The diagram means that class A depends on methods 1, 2, and 3 in interface I, and class B is an implementation of the dependency on class A. Class C depends on methods 1, 4, and 5 in interface I, and class D is an implementation of the dependency on class C. For both classes B and D, there are methods that are not needed (the ones highlighted in red), but they must be implemented because interface I is implemented. If you are not familiar with the class diagram, you can refer to the program code to understand it, 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(); 19} 19} 20 21 class B implements I{22 public void method1() {22 system.out.println (" class B implements interface 1"); 24} 25 public void method2() {26 system.out.println (" class B implements method2 "); 27} 28 public void method3() {29 system.out.println (" class B implements method3 "); 30} 31 // For class B, method4 and method5 are not required, but because they are in interface A, 32 // These two methods are implemented even if their method body is empty. 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 implements method1 "); 52} 53 // For class D, method2 and method3 are not required, but because they are in interface A, 54 // These two methods are implemented even if their body is empty. 55 public void method2() {} 56 public void method3() {} 57 58 public void method4() { 59 System.out.println(" method 4 of class D implements interface I "); 60} 61 public void method5() {62 system.out.println (" D implements method5 "); 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()); 78 77}}Copy the code

As you can see, if the interface is too bloated, the implementation class must implement any methods that appear in the interface, regardless of whether they are useful to the classes that depend on them, which is obviously not good design. If this design is modified to conform to interface isolation, interface I must be split. Here, we split the original interface I into three interfaces, and the design after splitting is shown in Figure 2:

 

(Figure 2 design following interface isolation principles)

As usual, post the code of the program for the reference of friends who are not familiar with the class diagram:

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(); 25} 25} 26 27 class B implements I1, I2{28 public void implements () {29 system.out.println (" class B implements I1 "); 30} 31 public void method2() {32 system.out.println (" class B implements I2 "); 33} 34 public void method3() {35 system.out.println (" class B implements I2 "); 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(); 51 {implements I1, i2 {51 public void implements () {51 system.out.println (" implements I1 "); 55} 55 public void method4() {56 system.out.println (" D implements I3 "); 58} 58 public void method5() {59 system.out.println (" D implements I3 "); 60}} 61Copy the code

The principle of interface isolation is as follows: Create a single interface instead of a large and bloated interface, refine the interface as much as possible, and contain as few methods as possible. That is, instead of trying to create a huge interface for all the classes that depend on it, we need to create interfaces that are specific to each class. In this example, the principle of interface isolation is used to change a large interface into three dedicated interfaces. In programming, relying on several specialized interfaces is more flexible than relying on one comprehensive interface. Interface is a “contract” set to the outside during design. By defining multiple interfaces in a decentralized manner, it can prevent the diffusion of external changes and improve the flexibility and maintainability of the system.

At this point, many people think the interface isolation principle is similar to the previous single responsibility principle, but it is not. First, the principle of single responsibility originally focuses on responsibility; The interface isolation principle focuses on the isolation of interface dependencies. Second, the single responsibility principle is mainly to constrain the class, followed by the interface and method, it is aimed at the implementation and details in the program; The interface isolation principle mainly restricts the interface interface, mainly for abstraction, for the construction of the overall framework of the program.

When using the interface isolation principle to constrain interfaces, note the following:

  • Keep interfaces small, but limited. It is true that refinement of interfaces can increase programming flexibility, but if it is too small, it can result in too many interfaces and complicate the design. So do it in moderation.
  • Customizing the service for classes that depend on the interface exposes only the methods that the calling class needs and hides those it doesn’t. Only by focusing on providing custom services for a module can minimal dependencies be established.
  • Improve cohesion and reduce external interactions. Make the interface do the most with the fewest methods.

When applying the principle of interface isolation, be sure to use moderation. It is not good to design an interface too large or too small. When designing interfaces, this principle can only be implemented accurately if you spend more time thinking and planning.