Howardism Musings from my Awakening Dementia
My collected thoughts flamed by hubris
Home PageSend Comment

Loosely Coupled Components, Part 1

I have mentioned often that one of the major keys to building good software components is independence… that is, having code that doesn't have dependencies on other code. This is all great in theory, but as soon as you have a component make a function call to another component, you have just created a dependency.

Of course you are now saying, how would you build an application if you can't hook components together… Function calls are only one way of integrating components together, we call this approach tight coupling.

There are places where tight coupling is fine. For instance, if you create a servlet that makes function calls and object instantiations from one or more components, you are creating a dependency where the servlet depends on these components. But servlets are generally application specific, and therefore not normally reusable, so such a dependency is usually acceptable.

However, if you have to get data from one component to another, then your servlet should get the data from the first component and pass it to the other component… don't get tempted to have the component pass the data directly, otherwise, you create an unnecessary dependency (see the following illustration).

Component Dependency Illustration

But what if you wanted to make your servlet (or other caller) independent? This is where we get into the realm we call loose coupling. The idea here is to instantiate and call components such that replacing the component doesn't require a recompile of the caller… or at least, not require the source code to be modified.

Think of a "plugin" where putting some code is a particular location and maybe editing a configuration file is all it takes to increase an application's features.

The two most popular techniques for this is using Reflection and Aspect Oriented Programming (AOP). In a feeble attempt at keeping these articles short, I'm going to break this up, and discuss using Java interfaces, and then later talk more about Reflection and AOP in follow-up articles…

Interfaces —

We have a few layers in loose coupling where some techniques are looser than others. The first level is using Interfaces, where instead of instantiating and calling an object directly, you use a Builder (design pattern) to instantiate an object that adheres to an interface, and then only call methods that are part of that interface. Let's have an example, shall we?

Let's pretend like we have a useful interface that defines a single method called "square" that computes the square of a number we give it. Something like this:

public interface PowerEngine {
    public long square (long value);
}

Now you need a factory that can determine (based on reasons unknown to the client) which class that implements this interface to instantiate and return to the client. It looks sort of like this:

public class PowerEngineFactory {
    public static PowerEngine  getEngine() {
       // Do some calculations and then
       return new PowerEngineA();
    }
}

A client would then use this code via:

PowerEngine eng = PowerEngineFactory.getEngine();
long power = eng.square(54);

What have we gained by this exercise? Well, it means that we can change an implementation of PowerEngine (even changing the name) without having to update the client. We also could have multiple implementations and have the factory figure out which would be the best response (often by reading at runtime a configuration file).

We have all used these sorts of factories as the Java API is full of them. In order to have a standard XML parsing library and yet allow anyone to implement a new version, we ask for an XML parser from a factory:

include javax.xml.parsers.*;
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();

In this case, every XML parsing library you may download and install implements this runtime factory. You can change a library implementation without altering your source code.

But doesn't a client now depend on the factory class, i.e. PowerEngineFactory? Yes it does. It also depends on access to the PowerEngine interface code. Granted, the factory classes usually don't change as much as the classes they return, but we still have more dependencies than we might like.

Before I talk about a more general solution using Reflection, let me clarify something:

You don't have to actually create an interface. You could create an abstract parent and have all of the implementing classes simply derive from this parent. Now your client will be expect an object of the parent class. However, I think it is clearer as to your intentions to create an interface.

Tell others about this article:
Click here to submit this page to Stumble It