Loose Coupling & Interfaces

What is loose coupling and why is it important? Let’s first discuss this concept in an abstract sense.Imagine a glove – it is “loosely coupled” to your body. Any kind of glove can be fitted on to any kind of body. The glove does not have any knowledge of a person’s body, nor does it care. It is not really connected to the person in question.  Now let’s say you wanted to change your skin colour. I’m sure you could imagine the painful and difficult process of removing your skin and attaching another. If you wanted a body with a different skin colour, you would have to make another one. This is the difference between tight and loose coupling in a nutshell.

  • Loose coupling: If you want to change the glove you’re wearing, you are not forced to change your body.
  • Tight coupling: If you want to change your skin, you would have to change your body.

 

Tight Coupling in Code

Let’s start off with an example of tight coupling in code. Take a look at the example below.

Do you notice anything about the code that stands out? If you take a look at the Car class you can see it takes a SmallEngine  object in its constructor. What if we wanted to make the Car class use RocketEngine ? We would need to go back and edit the class. This is not only bad architecture, but an example of tight coupling. Car  is dependant strictly on SmallEngine , yet RocketEngine  provides the same behavior (via its methods). How do we change this?

Loose Coupling in Code

We can define the actions of both RocketEngine  and SmallEngine through an interface. Think of an interface as a behaviour and the methods you define as actions which describe that behaviour. When defining methods in an interface, we only write the signature – no implementation code. You use the implements  keyword in Java to have a class use those methods. You are then responsible for writing the implementation code for each method.

Every Engine  works differently, yet they all provide the same basic functionality. You define the actions of an Engine  and then write the implementation for how that Engine  works. This example is very basic as we are only using System.out.println()  in each method. Just imagine a more complicated class, such as one responsible for fetching data from the web. Now you can see that Car  requires an Engine , but it doesn’t care what kind of Engine  it is. As long as the class we are passing is implementing the Engine  behaviour, we can use it for our Car .

Advantages

In case the advantages aren’t clear yet, I’ll try my best to explain. Initially our Car  was relying strictly on SmallEngine . What’s the big deal with just going back and changing the Engine  in the Car  class? Perhaps for this example, the amount of work required isn’t that much, but just imagine a large scale project with more than 100 classes. The required work in this case would border on mildly annoying to insanely arduous. Our Car  will still function correctly if we pass it an implementation of Engine . This is also known as separation of concerns. We do not need to worry about the possibility of our Car  breaking. We only need to make sure our Engine  is working correctly.

Programming to interfaces is something you should always try to practice. Now, mind you, not every class can or has to be an implementation of an interface. Try to do it where it makes sense. Loose coupling and having a separation of concerns in your codebase makes for one which is much easier to test.

Further reading:

More on coupling in Java

 

Liked the article? Share it!

Leave a Reply

avatar

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
Notify of