assertTrue is the professional blog of Luke Bayes and Ali Mills

Static Classes, Singletons and the Observer Pattern

Posted by Luke Bayes Sun, 15 Jul 2007 02:04:00 GMT

Over the years, Ali and I have spent quite a lot of time trying to sort out when to use static classes, when to use the Singleton pattern and when to do the work required to avoid them.

There has been a long and ongoing discussion in the OOP and patterns community on this subject by people far more intelligent and experienced than I am. It is really their knowledge and experience that will be essentially repackaged for ActionScript development here.

Following are the primary arguments that compel me to look for a better way.

Testable Code

Singletons make it incredibly difficult to effectively test other code. Let’s look at the most common Singleton that I’ve seen flailing around in ActionScript applications. The Singleton Service. The justification goes like this:

There is only one internet, but many of my objects need to access it, so I should hide my service interface behind a Singleton so that anyone can get at it any time.

Then you see methods like this:
public class MyFeature {

    public function doSomethingRemote():void {
        SingletonService.getInstance().doSomethingRemote();
    }
}
That doesn’t look so bad until you want to write a unit test for the MyFeature class. You now have to start jumping through hoops in your Singleton to figure out if you’re in the ‘test context’ or not. How do you switch out your live service with a stub?
Instead of reaching out to the global scope and retrieving a service, instances of this class should be handed a service when they are created.
public class MyFeature {
    private var _service:IService;

    public function set service(service:IService):void {
        _service = service;
    }

    public function get service():IService {
        return _service;
    }

    public function doSomethingRemote():void {
        service.doSomethingRemote();
    }
}
This model works great in plain old ActionScript, but particularly well in MXML where we can then have something like the following:
<MyService id="myService" url="http://www.example.com/api" />
<MyFeature service="{myService}" />
Execution Context

Singletons, like globals (yes, I’m glaring in the general direction of ‘_root’) create context dependence.

This means that when your execution context changes, you have unexpected outcomes. For example, when you load an application that relies on Singletons into another application, whose Singleton gets used? If you’ve done any reading on ApplicationDomain, you’ll see that it really depends. Being unclear about which Singleton you’re using is absolutely not desirable as many of us learned the hard way back in the dark days of unrestrained _root usage.

Execution context is related to the testable code argument in that your test harness is simply another context in which your code is expected to run. It is different for those of you who aren’t writing tests (you know who you are), but should still be aware of the likely fact that your application may be executed in some unexpected context.

You may want to be thinking about Adobe AIR right now, okay not that one, this one.

There are a number of additional arguments against using Singletons, but these two are the strongest and, in my experience, the most applicable to ActionScript development.

What it really comes down to is that the assumption, “I only ever want one of these,” is almost always proven wrong with time.

Consider the Mouse and Keyboard. One might think that these interfaces should be Singletons, but they would be wrong! Consider Monitors – some of us remember when there could be only one! How about the Operating System itself? Anyone using Parallels?

Just about anything you can think of that might appear to be a Singleton will turn out to be context dependent.

Static Classes

So if Singletons are so bad, should I just use static classes?

Absolutely not! Static classes carry with them all of the problems of Singletons and then some. Admittedly, I have used static classes in the past for things like math utilities or string utilities. These are features that will not be impacted by a change in context and additionally will gain very little from polymorphism.
Basically, if I’m writing a static class, I work hard to adhere to the fundamental principles of functional programming.

If I send value a to this function and it returns value b once, then every time I send it value a in the future, it must always return value b.

Simply put, this means that the object has no internal state that may change the return values of a method. These kinds of classes tend to be useful and do occasionally make sense. If you want to expose some algorithms or constant values throughout your application and feel it would be too time-consuming to inject a helper instance all over the place, go for it – but you should feel bad about it.

The Observer

I felt compelled to write this article because I keep seeing smart, experienced people create (and worse – encourage others to create) Singleton and static EventDispatchers. This is unequivocally a bad idea. If your objects need to reach out to the global scope in order to subscribe to or broadcast some event, you need to do some deep reading on the benefits of Inversion of Control and the Composite pattern.

In Closing

In my opinion business-driven schedules are the only valid justification for using the Singleton pattern, and even then it often winds up costing the business more than it saved. Singletons and static classes usually indicate technical debt and a failure of intellectual rigor.

In general, if I don’t understand the problem at hand well enough to avoid globals I should probably stop writing code until I do. The urge toward Singletons is usually a good moment to step back and reexamine the current design. Alternatively, the appearance of static classes that hold state are like an alarm screaming for me to immediately stop writing code and consider my choices.

In spite of this criticism anyone digging through enough of my own code will surely find both of these smells waiting for them and should at least know that I didn’t go down without a fight.

Tags , , ,  | 3 comments | no trackbacks

Comments

  1. Ben replied: Avatar Great article, even though it makes me a bit ashamed. :) Some of the issues facing Cairngorm and Modules integration can definitely be attributed to Singleton usage. Though I definitely think static classes are valid for holding strings that will never change.
    Posted: 1 day later.
  2. Tony commented: Avatar Singletons do have their place. The key to writing really beautiful OO code is to try and make your objects match the "real world" model as much as possible. If something is singleton in reality then it should be singleton in the software model. (I know that most of the time we're not mapping software objects onto real objects, but hopefully you get my point)
    Posted: 1 day later.
  3. Luke Bayes replied: Avatar Hey Tony, I definitely agree with the plausibility of your statement, but want to make a couple of counter points:

    1) Things that *seem* in reality to have only one instance often multiply with time (Mice, Monitors, and Networking hardware to name a few).

    2) If you really only want one instance of something, dependency injection is often a better and less limiting way of accomplishing this.

    3) Singleton usage does make automated testing of it's consumers much harder.
    Posted: 1 day later.

Trackbacks

Use the following link to trackback from your own site:
http://www.asserttrue.com/articles/trackback/1436

Your Reply

Comment Form.

Fields denoted with an "*" are required.