Loose coupling

When I first started learning about object oriented programming, and really digging into the best practices, loose coupling and high cohesion kept cropping up.  I had a hard time trying to keep them straight and remember which one I wanted more of and which one I wanted to reduce.  My biggest difficulty was I couldn’t keep the definitions of coupling vs cohesion straight!

Coupling refers to how much a set of classes rely on one another.  If we have two classes, A and B that each use methods from the other, these classes would be tightly coupled.  If we have those same two classes and only one needs methods from the other, then those are more loosely coupled.

The little metal ends on a garden hose that you can twist together are called couplings.  You use them to join two pieces of hose together.  I like to use this to help me remember that coupling is about how two (or more) classes interact with one another.

Cohesion refers to how much the methods in a particular class belong together.  For example, let’s say we have a class representing a soup can.  The soup can should know about how big it is, what it is made out of, what shape it is and what color it is.  If we start adding information about the soup that is stored inside the can, then we are breaking the cohesion.  Information about the soup is not important to the actual can.  The information about the soup should be contained in a separate class that the can could know about.

Thinking about a cohesive group of people helps me remember what this means.  A cohesive group of people are people that work very well together and really seem to belong together, much the same way as a cohesive class design has methods that really belong together.

Loose Coupling

Today we are only going to talk about coupling.  We will save the discussion about cohesion for another day.

Now that we know that coupling refers to how much classes know about each other, let’s dive into why we want loose coupling in the first place.  Why do we want our classes to know as little as possible about each other?

Let’s pretend for a moment that we are trying to capture, in code, a peanut butter sandwich.  The simplest way to represent this would be to have a Sandwich class that contains an instance of a CreamyPeanutButter class and two instances of Bread.

public class CreamyPeanutButter {
    private int amount;
    public CreamyPeanutButter(int amount) {
        this.amount = amount;
    }
}

public class Bread {
    private CreamyPeanutButter creamyPeanutButter;
    public void addPeanutButter(int amount) {
        creamyPeanutButter = new CreamyPeanutButter(amount);
    }
}

This is very straightforward, right?  Now, let’s add a new type of peanut butter into the mix.  CrunchyPeanutButter.  We want to be able to add either Creamy or Crunch peanut butter to our sandwich.  One way to accomplish this might look something like this:

public class CreamyPeanutButter {
    private int amount;
    public CreamyPeanutButter(int amount) {
        this.amount = amount;
    }
}

public class CrunchyPeanutButter {
    private int amount;
    public CrunchyPeanutButter(int amount) {
        this.amount = amount;
    }
}

public class Bread {
    private CreamyPeanutButter creamyPeanutButter;
    private CrunchPeanutButter crunchyPeanutButter;
    public void addPeanutButter(String type, int amount) {
        if ("creamy".equals(type)) {
            creamyPeanutButter = new CreamyPeanutButter(amount);
        } else if ("crunchy".equals(type)) {
            crunchyPeanutButter = new CrunchyPeanutButter(amount);
        }
    }
}

If you compare our new Bread class to our previous one, you can see that the new one is a lot more complex, and really has to understand a lot about peanut butter.  This is a code smell telling us that these two classes are too tightly coupled.  Bread should know about bread, and not about peanut butter if it can avoid it.

What can we do?

The code above has a lot of code smells.  The first one, I noted above, was that any change to add a new type of peanut butter, or change the peanut butter classes is going to cause us to have to change our bread class.  This is what tight coupling does, and what we want to avoid.

Another code smell, however, is the duplicated code between the two peanut butter classes, they both have the same constructor.  We could remedy this by creating an ancestor that they inherit from.  This step will also allow us some additional refactorings on our Bread class.

public abstract class PeanutButter {
    private int amount;
    public void setAmount(int amount) {
        this.amount = amount;
    }
}

public class CrunchyPeanutButter extends PeanutButter {
}

public class CreamyPeanutButter extends PeanutButter {
}

We changed the two classes to use default constructors, and instead added a setter to set the amount.  Now, we only have one place where we keep track of the amount, rather than duplicating the code across all of our peanut butter instances.

This change can now allow us to make some updates to our Bread class to reduce the coupling there.

public class Bread {
    private PeanutButter peanutButter;
    public void addPeanutButter(PeanutButter peanutButter, int amount) {
        this.peanutButter = peanutButter;
        this.peanutButter.setAmount(amount);
    }
}

We’ve made several simplifications to the Bread class here.  First, we changed our method signature for “addPeanutButter” to take in the type of peanut butter we want to add.  This allows us to get rid of the ugly if/else clause we had in there before, and allows us to have a single instance variable to hold the peanut butter.  Then, we simply set the amount that is passed in, and make sure that our instance variable is set to the type that is passed in.

With this change, we could easily add new types of peanut butters, as long as they inherit from the PeanutButter class without having to touch our Bread class.

Summary

Of course there are additional steps we could take to reduce the coupling of the above classes even further, and allow our Bread class to be used in sandwiches of different types.  But, hopefully this simple illustration is enough to show some of the power behind keeping our classes loosely coupled.

Advertisements

One thought on “Loose coupling

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s