Day 19: Avoid Singletons
Design patterns exist to solve common problems found on the development of object oriented software. As such, the singleton pattern exists to satisfy the need for code that is available to the whole application. It also helps when we want to enforce that only one instance of an object exists during the lifetime of the application.
The problem with the use of singletons is that the requirements above contradict a lot of the paradigms of object orientation. First of all, if some code is available to the whole application without creating objects, it can just be viewed as a structured piece of code, which could be easily implemented as a set of functions.
If one doesn’t need to create or destroy objects, then there is no need to use an object in the implementation, unless you’re using a language such as Java that has only objects.
As seen above, singletons don’t pass the ‘smell’ test of a pattern for the creation of solid code. Despite this, singletons were once a celebrated design pattern. A lot of singletons can be found everywhere in modern code. It is necessary, however, to be aware of some of the problems you will find when using them:
- Singletons are hard to test: Since it is difficult to have any control about how the singleton is created, testing of a singleton in a controlled setting becomes very complicated. Sometimes, a singleton assumes a lot about the programming environment to work properly, and as a result it is not possible to create one of them in isolation.
- Hard to reuse: for the same reason given above, singleton’s are hard to integrate to other code. They become non-reusable because they have to assume so much about the environment of any single program.
- Allow indiscriminate use of resources: another big problem is hat there is no simple way to localize the use of a singleton. Once it is available, it can be used by the whole application, by definition. This has implications in the areas of safety, as well as in avoiding mistakes in the use of this shared resources.
Although singletons are in use in so many places, it is possible to avoid them in many occasions. Here are a few tactics that you can use to get rid of unnecessary singletons.
- Convert into standard classes when possible: sometimes it is not so much work to convert a singleton into a traditional class. Just make sure that the initialization is done only when the first object is created. If there is a single resource that needs to be shared, for example, a network connection, you can use a static member variable to store that resource. In this way, you can have multiple objects that are still referring to a single resource.
- Use static member functions in some cases: sometimes a singleton is improperly used when just a few static methods would work. This is a case when it is easy to remove the singleton, because there is no central resource that is shared. While static methods are not the best thing in the world, they at least are easier to test than a monolithic object.
- Determine where the singleton is used. Sometimes it is applicable to just a small part of your app. When that happens, create a class that may used only by that part of the application. For example, if you using C# that might be a class visible only to the package. In this way, you avoid the indiscriminate access provided by singletons.
- Factor the singleton into two or more classes: sometimes the options above are not available. But it is still possible to reduce the functionality of the singleton and provide them with two or more classes. A few of these classes can be non-singletons, which are easier to test. While this won’t solve the whole problem, it may simplify development and testing of the application.
- Make the singleton as small as possible: As a last resort, use the tactic above to remove all the functionality that is not strictly necessary from the singleton. Even if you cannot test the singleton in isolation, you make it very small and easier to understand. This also remove the temptation of adding even more functionality to an existing singleton.
The singleton pattern has a number of deficiencies that make it difficult to integrate with other programming practices. Therefore, it makes sense to restrict its use only to situations when it is strictly necessary. You should investigate some of the ideas above to reduce or eliminate the use of singletons in your code, and as a result, improve the testability of the application.
The Gang of Four book is the original source for everything design patterns. You should check carefully the rationale for using singletons.
About the Author
Carlos Oliveira holds a PhD in Systems Engineering and Optimization from University of Florida. He works as a software engineer, with more than 10 years of experience in developing high performance, commercial and scientific applications in C++, Java, and Objective-C. His most Recent Book is Practical C++ Financial Programming.