Skip to content
Advertisement

What does decoupling two classes at the interface level mean?

Lets say we have class A in package A and class B in package B . If object of class A has reference to class B, then the two classes are said to have coupling between them.

To address the coupling, it is recommended to define an interface in package A which is implemented by class in package B. Then object of class A can refer to interface in package A . This is often an example in “inversion of dependency”.

Is this the example of “decoupling two classes at the interface level”. If yes, how does it remove the coupling between classes and retain the same functionality when two classes were coupled?

Advertisement

Answer

Let us create a fictive example of two classes A and B.

Class A in package packageA:

JavaScript

Class B in package packageB:

JavaScript

As we see, A depends on B. Without B, A cannot be used. We say that A is tightly coupled to B. What if we want to replace B in the future by a BetterB? For this, we create an Interface Inter within packageA:

JavaScript

To utilize this interface, we

  • import packageA.Inter; and let B implements Inter in B and
  • Replace all occurences of B within A with Inter.

The result is this modified version of A:

JavaScript

We can see already that the dependency from A to B is gone: the import packageB.B; is no longer needed. There is just one problem: we cannot instantiate an instance of an interface. But Inversion of control comes to the rescue: instead of instantiating something of type Inter within A‘s constructor, the constructor will demand something that implements Inter as parameter:

JavaScript

With this approach we can now change the concrete implementation of Inter within A at will. Suppose we write a new class BetterB:

JavaScript

Now we can instantiante As with different Inter-implementations:

JavaScript

And we did not have to change anything within A. The code is now decoupled and we can change the concrete implementation of Inter at will, as long as the contract (s) of Inter is (are) satisfied. Most notably, we can support code that will be written in the future and implements Inter.


Adendum

I wrote this answer in 2015. While being overall satisfied with the answer, I always thought that something was missing and I think I finally know what it was. The following is not necessary to understand the answer, but is meant to spark interest in the reader, as well as provide some resources for further self-education.

In literature, this approach is known as Interface segregation principle and belongs to the SOLID-principles. There is a nice talk from uncle Bob on YouTube (the interesting bit is about 15 minutes long) showing how polymorphism and interfaces can be used to let the compile-time dependency point against the flow of control (viewer’s discretion is advised, uncle Bob will mildly rant about Java). This, in return, means that the high level implementation does not need to know about lower level implementations when they are segretaget through interfaces. Thus lower levels can be swapped at will, as we have shown above.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement