Design Patterns: The Singleton
Design Patterns, Programming, Software Patterns May 16th, 2007 - 8,878 viewsGlobal variables tie classes to context and create unnatural interdependencies in an application. A Singleton ensures that a class only has one instance, and provides a global point of access to it. If a system only needs one instance of a class, and that instance is used in different parts of the system, you can control instantiation and access by making the class a singleton.
The Problem
Global variables are often the bane of modern software development projects. Many classes need to be accessible from anywhere within an application. Classes that encapsulate configuration details, database access, or logging are required throughout an application. But relying on global variables couples the class with the current application, undermining encapsulation and making the class less reusable. If you were to try to use the class in a different context you would need to be sure that the same global variable is available, and properly instantiated.
Rather than creating global variables, well designed object-oriented systems generally pass object instances around via method calls. This has the benefit of making the collaboration explicit: it’s clear that the object depends on the data because it is part of the method’s signature. The problem with this approach is that it sometimes requires you to use classes as a sort of conduit, passing objects around that they never use, and creating unnecessary dependencies.
The Singleton pattern distinguishes itself from normal global variables by inverting the responsibilities of the global data and the client that uses it. With the Singleton pattern, the global class itself is responsible for keeping track of its sole instance. It ensures that multiple instances are not created by intercepting requests to create a new object, and provides a way to access its single instance from anywhere. Collaboration is explicit, because the client retrieves the data from a method of the singleton class. But dependencies are reduced, because classes that are not interested in the global data no longer need to worry about it.
Implementation
To implement the Singleton pattern you need to somehow assert control over object creation. This is actually pretty simple to do in most languages: simply define a private (or protected) constructor. In PHP it looks something like this:
class Configuration {
private $config = array();
private function __construct() { }
public function setOption( $option, $value ) {
$this->config[$option] = $value;
}
public function getOption( $option ) {
return $this->config[$option];
}
}
Because the constructor is declared private, client code cannot instantiate an object of the class. We can use a static method and a static property to mediate object instantiation, giving client code access to the global data throughout the application while ensuring that only one instance of the class is ever created:
class Configuration {
private $config = array();
private static $instance;
private function __construct() { }
public static function getInstance() {
if( is_null( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
public function setOption( $option, $value ) {
$this->config[$option] = $value;
}
public function getOption( $option ) {
return $this->config[$option];
}
}
Because the Configuration::getInstance() method is public and static, it can be called from anywhere in the system that configuration data is required.
Consequences
Like global variables, Singletons can create dependencies that are difficult to find and debug. Normally, dependencies are obvious because they are declared as part of a classes interface (i.e. as arguments to a method). But with the Singleton, dependencies are hidden in the implementation. This can make it difficult to track all of the relationships in a complex system.
That said, the Singleton has many benefits. It can be used for lazy instantiation of objects (i.e. the object is only instantiated when it is first used), as the example above shows, which can be a big benefit for classes that use constrained resource like database connections. It also permits you to limit the number of instances to some number greater than one (sometimes called a Multiton), which can be useful for opening some limited number of I/O streams, for example.
The Singleton pattern is a definite improvement over global variables in an object-oriented system, and moderate use of this pattern can improve the design of a system. Singletons are related to the Abstract Factory, Prototype, and Factory Method patterns which I’ll be discussing in future posts. If you’re interested in learning more about these related patterns, you can subscribe to my feed.
May 17th, 2007 at 4:05 am
In general, it doesn’t matter much whether you can actually instantiate the class more than once, but whether you will do that in the normal course of operation.
As I said in a comment on another post, it may make sense to instantiate the class in a unit test. Guice, a dependency injection framework, supports Singletons, in that when you denote something as a Singleton, Guice will always give you the same instance. The class itself doesn’t need any extra boilerplate for this, and Guice doesn’t prevent you from bypassing it to instantiate the class directly.
In other words, by encouraging best practice rather than disallowing (what they consider) worst practice, they are working with the developer instead of trying to imprison him.
“The problem with this approach is that it sometimes requires you to use classes as a sort of conduit, passing objects around that they never use, and creating unnecessary dependencies.”
Absolutely. Did you invent this? I’d realised it but I’ve never seen it written before. I’ve seen students struggle with the idea of reference passing, so much so that, in Java, I encourage them to write event handlers as local classes rather than external ones, passing the required references across through the constructor.
Previously, I thought local classes were a harder concept than reference passing, but that’s probably only because I met reference passing before local classes.
May 17th, 2007 at 9:12 am
Ricky,
As usual I agree with about 80% of what you said :). You have obvious gripes with code duplication (as any programmer should) and I’d just like to point out that implementing the Singleton pattern in PHP takes a full 8 lines of code - it’s not nothing, but it’s not enough for me to start getting concerned either. Plus, by making the Singleton you’ll often reduce duplication elsewhere (because client code doesn’t have to check that the global data has been prepared).
The bit on being a conduit is something I’ve picked up from several patterns books, and obviously from experience. I think this is a common problem many new programmers face: they know they need a certain piece of information in a certain place, but they’re not sure how they should get it there.
Re: your comment on unit testing - I typically do a full tear-down/build-up of all of my instantiated objects for each unit test in order to ensure things don’t “leak” between tests. So I’m wondering, when would you need a Singleton to not be a Singleton for a unit test?
May 17th, 2007 at 10:27 am
To do something twice, implement it once and call it twice. If you cannot, then there is something wrong with the language. If you can, but do not, then there is something wrong with you (ok, grey area). You have not reached the guts of whatever problem it is you’re solving if you have duplication in your solution.
Of course, some things are harder than others to make reusable. I’d like to see tools that can spot duplicates AND prompt you with ways of resolving those (or even, later, do them automatically).
The other problem is that sometimes you need a name for something, and you cannot come up with a good one. In those cases, you are perhaps looking at too high or low a level, and should remove duplication in a different way, or you should do your best to localise the bad name. For example, see this Lisp code[1] - I couldn’t come up with a good name for the macro, so I called it def (thanks to someone from #lisp) and used a macrolet to make the name def have very limited scope.
About Singletons reducing duplication - I think you mean the global point of access reduces duplication. If you made $instance public, and initialised it as soon as it’s declared, then you’d have a global point of access, and you wouldn’t necessarily need that to be a singleton.
You could equally well have two global points of access, i.e., two instances.
For unit testing, you might need a Singleton not to be a Singleton if it has any state, to ensure that things don’t leak between tests, like you said. Oddly, you almost seem to answer your own question there. ;)
[1] http://paste.lisp.org/display/41241#1
May 17th, 2007 at 3:53 pm
Ah, I see what you’re saying about unit tests now. But when I unit test I typically tear down and rebuild the entire application if I need to change state and ensure nothing leaks. If you do that, you don’t need the Singleton to not be a Singleton!
You mentioned making $instance public and initializing it as it’s declared. What would be the benefit to that over the Singleton pattern. You’re doing essentially the same thing, except that you’re breaking encapsulation and losing some flexibility. You’d no longer be able to lazy load your instance, and you’d be locked in to a single implementation. With the Singleton pattern you can, for example, dynamically decide to instantiate a different subclass instead of using the default instance.
I just finished a post about the Front Controller, which is a much higher-level pattern. I’d be interested in hearing your thoughts on it.
May 17th, 2007 at 4:01 pm
In Java, with a typical singleton implementation, you couldn’t tear down the singleton without restarting the JVM (or doing some strange things with classloaders). That’s rather inconvenient between unit tests. I already do too much at the start of most unit tests (in time, not code).
If I make $instance public, what am I exposing that wasn’t exposed before? The field? It’s the same data, just accessed differently. And what flexibility am I losing? How does this lock you in when a method call doesn’t?
I don’t know about PHP, but Java loads classes in only when you need them, so it effectively does the lazy loading for you.
“With the Singleton pattern you can, for example, dynamically decide to instantiate a different subclass instead of using the default instance”. That’s fine. $instance=dynamicallyDecideWhatSubclassToUse();
I’ll head on over to the Front Controller post.
May 17th, 2007 at 4:50 pm
By making $instance public you’re losing the ability to change your implementation (e.g. how $instance is instantiated, and what implementation $instance uses). With the method, you’re only locked into an interface. Exposing the variable locks you into an implementation.
It’s true that you could just decide what type to load elsewhere but, in my opinion, it makes more sense to make that decision in the class. The client code shouldn’t need to know what the implementation is, it should only need to know the interface.
Java only loads classes when you need them, yes, but that’s not what I was talking about. I’m talking about lazy instantiation. I use a Singleton for my database connections in web apps, for example. When I call the getInstance() method for the first time I initialize the connection. If some page doesn’t need a database connection, getInstance() is never called and the connection is never made, which is A Good Thing.
Without the method you have a few options:
1. You can instantiate the global object the first time you use it. But then you need to know in advance when the first time you use it is going to be. That’s not always clear. And if you change when that “first time” is, you’ll need to go back and change the old code that instantiated it (possibly in multiple places).
2. You can instantiate the global objects very early on in your application, before anything else is done. The problem here is, like I said before, you might be instantiating objects that are never used.
3. You can check to see if the object is already instantiated every time you use it, and instantiate it if it’s not. This is basically what you’re doing with the Singleton pattern. Except, as I said in the article, the responsibility for instantiation is inverted. The class itself is reponsible for instantiating the object, so you only have the conditional logic ( if(is_null($instance) … ) in one place. Again, this is A Good Thing.
None of these solutions are ideal. The Singleton approach is a much more elegant solution (IMO). The benefits might not be _massive_, but the cost of using this pattern is almost zero. Like I said, it’s 8 lines of code.
August 16th, 2007 at 3:00 pm
Convenience is not a good reason to use global objects of any type. Singletons are restrictive and make for an unmaintainable mess. Make an instance as high as the OS entry point if need be and pass it to the objects that _need_ it.
First google hit:
http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx