A little while back, I blogged about how static and singleton are not synonymous, and one of the things I mentioned in there was the concept of an “access pattern”. This is a term I’ve been kicking around for a while (in person, anyway… I think that was the first time I’d written about it), and I wanted to explore it a bit more here.
A creational pattern describes how you create instances of objects. Examples of this include the Factory Method, Factory Class, Abstract Factory, and, of course, the infamous Singleton. Access patterns, by contrast, describe how you get hold of an instance which already exists. Examples of this include registries (ala JNDI), blackboards, dependency injection, and, of course, static methods.
Note that neither technique requires enforcement. In some languages enforcement isn’t even possible. In more B&D-ish languages such as Java, C++, and the latest member of the family, C#, it’s possible to semi-enforce (though you can bypass these restrictions if you really work at it)[1].
In any case, with a creational pattern, you end up creating instances. The question then becomes how do you use them. This is where access patterns come in.
The primary point of creational patterns, BTW, is to decouple the type of an object from the class of an object. An object only ever has one class; this is the implementation that is instantiated. However, objects may have several types. In Java, for example, a String object has five types; Object, CharSequence, Comparable, Serializable, and, of course, String. By using a creational pattern, you can separate the concern of what exactly an object is (which class is it) from the question of how you use it (the type you care about). Coding to types instead of classes is a big part of good OO design; indeed, about the only time you should really care about the exact implementing class tends to be when you instantiate one.
However, decoupling the type isn’t all you can do to improve matters. You can also decouple the lifecycle; the actual creation of the instances themselves. This tends to be the role of the access pattern. This is used throughout the J2EE spec, for example, in the java:comp/env JNDI namespace. At one extreme, you go to dependency injection, where classes don’t instantiate things at all, just about; instead, they are giving instances that already exist (“Here’s one I prepared earlier…”)
You can’t just ignore an access pattern simply because you’ve used a creational pattern. After all, at the very least, you need a way to access that shiny new Factory Object that you want to use to create all your instances. It’s very easy to have a design where the factories themselves become chokepoints. When you draw these up, the symptom is obvious: lots of lines pointing at the factory class.
To my mind, this is where Singleton trips up, particularly in Java. It’s just too easy to make the Singleton a static variable (final or otherwise) and refer to it directly (or almost directly… Foo.getInstance() is only marginally better than Foo.INSTANCE)[2]. Sure, there is a degree of decoupling, but it’s like you’ve cut one rope and gained about a metre of slack; you’re still tied up. In any case, the problem is that instead of handing around the instance itself, people have a strong tendancy to hand around the way to “create” the instance; this, of course, is a disconnect between the creational pattern and the access pattern.
As I become more experienced in OO design (and I certainly don’t call myself an expert in it yet…), I become aware of the degree of coupling between objects, and I want to try and reduce them as much as possible. Thus if I have a choice between being given an instance, or looking up an instance, or creating an instance, I tend to go from left to right. If my class doesn’t need to create an instance, or doesn’t need to know where to look one up, then why should it know that? Just get given one by another class that does have that responsibility. Dependency injection techniques are, of course, the most extreme form of this.
A little while back, Michael Feathers of ObjectMentor proposed a touchstone for OO design. This rule is very simple:
Pick a class, any class, and try to instantiate it in a test harness.
The greater the degree of coupling, the harder it is to do this. A corollary to this is that you need to be able to give the instance suitable versions (quite probably fake) of its dependencies so you can test behaviour. The more knowledge you build into an object about how to create or access dependencies, the harder this is to do.
A concrete example, as that can often make things clearer:
I have an object that needs to save something to a database. Ultimately, it needs a datasource pointing at a specific database, so it can execute SQL over a connection. Now, I can decouple it in several ways. The first, and easiest in a J2EE setup, is to obtain the datasource from a registry. This, in turn, can be made into a decoupled registry, via the java:comp/env namsepace. At this point, I no longer care about how the datasource is made; as far as my object is concerned, there is a datasource that I can access.
Why does my object want to access a datasource? Because it needs a database connection. If I access the datasource to create the database connection, then I need to manage the connection lifecycle; in particular, I need to make sure the connection is closed and released (e.g. back to the connection pool). This sort of code results in a lot of try { … } finally { … } blocks, where people endevour to ensure that the connections are managed appropriately. This works well to start with, but can cause problems later. A good example of that would be if I wanted to do a few database interactions in a single transaction, and my object needs to play nicely in that context.
If, instead, I simply make the connection a dependency of the object, then I can require that the connection be provided to “me”[3]. This pushes the responsibility of the lifecycle management of the connection to someone else, and lets me focus (right now) on the persistence logic. This, in turn, makes it very easy to unit test, because I don’t need a database. I can supply a fake connection that verifies the SQL, and quite possibly sets up error conditions such as lock violations or duplicate keys.
In this example, we’ve gone from a pure creational pattern (create a datasource) to a mixed access/creational pattern (access a datasource to create a connection) to a pure access pattern (access a connection, via dependency injection).
There’s more I could write on this topic, and I probably will later. However, for now, it’s getting late, so I’m going to leave it here. I hope that this is of interest and use to someone; I’m personally finding it very valuable as a way of organising my own thoughts, and while this is enough, there’s a lot of gratification to be had when others can gain from what I’ve got to say.
[1] Personally, I’m not a fan of enforcing a design pattern. The need to enforce any particular rule, in life generally, is inversely proportional to the number of people who see the sense in the rule and agree with it. Of course, they first have to be aware of it… In any case, I’m a fan of following a consensus, but sadly this isn’t always possible (for example: high turnover on a project may make consensus design decisions difficult to maintain). One of the nicer things about pair programming, as an aside, is the way it helps spread and maintain consensus viewpoints.
My reasons for not liking enforcement centers around the subsequent loss of flexibility; I find that any option I rule out tends to be the one I need later.
[2] The other reason this trips up is because static does not actually give you a true Singleton. All that a static variable or method gives you is an instance associated with the class instance; this means different things depending on what the class loader rules in force are. By a semi-happy coincidence, this is close enough to being a Singleton for most style of apps, but not all. In J2EE development in particular, class loader quirks cause more problems for novice developers than any other aspect of the technology (IMHO, of course)
[3] Yes, I tend to write about objects in the first person; I find it easier to visualise the relationships if I look at them from the object’s perspective.