Singleton Design Pattern: Pitfalls

What are drawbacks or disadvantages of singleton pattern?

Paraphrased from Brian Button:

  1. They are generally used as a global instance, why is that so bad? Because you hide the dependencies of your application in your code, instead of exposing them through the interfaces. Making something global to avoid passing it around is a code smell.

  2. They violate the single responsibility principle: by virtue of the fact that they control their own creation and lifecycle.

  3. They inherently cause code to be tightly coupled. This makes faking them out under test rather difficult in many cases.

  4. They carry state around for the lifetime of the application. Another hit to testing since you can end up with a situation where tests need to be ordered which is a big no no for unit tests. Why? Because each unit test should be independent from the other.

Singleton Design Pattern: Pitfalls

Singleton is generally a bad idea if you are doing unit testing, and its generally a bad idea not to do unit testing (or BDD or Acceptance Testing).

Making objects have global state means that the unit tests you write involving these objects will be isolated and disjoint from one another. Instead, you will have to worry about resetting the state for each test and believe me ... that is never done 100% of the time. If you don't reset the global state then you start to get very weird and hard to debug errors in your tests that waste time.

Global state also increases coupling in your code and makes it very hard to refactor.

The ideal method would be to use an IoC/DI container (Spring, Guice, etc.) to request objects. These containers often have ways of making objects appear as 'Singletons' but they also have ways of modifying that behavior depending on the situation (i.e. unit testing vs. your domain code).

This all depends on the size of your problem of course. If you're hacking together a 4-class test rig to try something out then go ahead and use a Singleton. However, as soon as that project takes on life and grows bigger and more complex then refactor the Singleton out.

Why is Singleton considered an anti-pattern?

To help with answering, here is more about the anti-pattern comment:

it is overused, introduces unnecessary restrictions in situations
where a sole instance of a class is not actually required, and
introduces global state into an application

From: http://en.wikipedia.org/wiki/Singleton_pattern

For more on this you can look at: https://www.michaelsafyan.com/tech/design/patterns/singleton

Here is a great ending to the blog above:

In short, the singleton pattern makes code more complex, less useful,
and a real pain to re-use or test. Eliminating singletons can be
tricky, but it’s a worthwhile endeavour.

OK, so, the reason it is an anti-pattern is described well in this paragraph, and, as the author expresses, it tightly couples your code to the singleton.

If you find that you want to use a singleton, you may want to consider your design, but there are times where it is useful.

For example, once I had to write an application that could have at most one database connection, to process thousands of requests. So, a singleton makes sense since I am resource constrained to having only one instance.

But, generally this is used to simplify code, without thinking of the difficulties that will be introduced.

For example, and this applies to static classes also, if you unit test, or have concurrency, then the state of one request will change the state and that may cause problems, as the class calling the instance may be assuming the state is as it expected.

I think the best way to challenge the use is to think of how to handle it if your program is multi-threaded, and a simple way to do that is to unit test it, if you have several tests that run at one time.

If you find that you still need it, then use it, but realize the problems that will be encountered later.

singleton pattern performance drawbacks

An important part of designing big software systems is to minimize the coupling between components and classes. This can be done through the encapsulation of the implementation of different components. The more components know about each other the higher is the dependency between them.

Using the Singleton Pattern means to be coupled to an implementation class (not to an interface, or to an abstraction). It would be better that each component that is using the GameManager would use a GameManagerInterface instead, so that the implementation can be easily changed or extended. Hiding the dependency to the concrete Singleton Class is difficult because somewhere you have to call the static method.

...
IGameManager iGameManager = GameManager.getInstance();
...

Using the Singleton Pattern like this is... :

 GameManager.instance.someOtherClass.someVariable     

... is never a good idea. Doing so would couple the calling class to the implementation of each of the called classes. Its best to only communicate with your direct neighbours as said in the "Law of Demeter"
(a.k.a. "Tell Don't Ask", or "Don't Talk to Strangers").

Maybe for you its time to think about the purpose of the Singleton Pattern: The Singleton Pattern is used to ensure, that there is only one instance of a Class. Nothing more.

Using the static "getInstance" method everywhere in your code leads to hidden dependencies as mentioned before. What you are doing is to use the Singleton Pattern as a replacement for a global variable. This makes your system fragile, because every bit of your code is dependant of the implementation of the singleton class. Changing this class could crash your whole system.

Problems with Singleton Pattern

In a garbage collection environment it can be an issue with regards to memory management

In typical singleton implementations, once you create the singleton you can never destroy it. This non-destructive nature is sometimes acceptable when the singleton is small. However, if the singleton is massive, then you are unnecessarily using more memory than you should.

This is a bigger issue in languages where you have a garbage collector (like Java, Python, etc) because the garbage collector will always believe that the singleton is necessary. In C++, you can cheat by delete-ing the pointer. However, this opens its own can of worms because it's supposed to be a singleton, but by deleting it, you are making it possible to create a second one.

In most cases, this over-use of memory does not degrade memory performance, but it can be considered the same as a memory leak. With a large singleton, you are wasting memory on your user's computer or device. (You can run into memory fragmentation if you allocate a huge singleton, but this is usually a non-concern).

In a multithreaded environment it can cause bottlenecks and introduce synchronization problems.

If every thread is accessing the same object and you are using a mutex, each thread must wait until another has unlocked the singleton. And if the threads depend greatly upon the singleton, then you will degrade performance to a single-thread environment because a thread spends most of its life waiting.

However, if your application domain allows it, you can create one object for each thread -- this way the thread does not spend time waiting and instead does the work.

Headache from testing prespective.

Notably, a singleton's constructor can only be tested once. You have to create an entirely new test suite in order to test the constructor again. This is fine if your constructor doesn't take any parameters, but once you accept a paremeter you can no longer effective unit teest.

Further, you can't stub out the singleton as effectively and your use of mock objects becomes difficult to use (there are ways around this, but it's more trouble than it's worth). Keep reading for more on this...

(And it leads to a bad design, too!)

Singletons are also a sign of a poor design. Some programmers want to make their database class a singleton. "Our application will never use two databases," they typically think. But, there will come a time when it may make sense to use two databases, or unit testing you will want to use two different SQLite databases. If you used a singleton, you will have to make some serious changes to your application. But if you used regular objects from the start, you can take advantage of OOP to get your task done efficiently and on-time.

Most cases of singleton's are the result of the programmer being lazy. They do not wish to pass around an object (eg, database object) to a bunch of methods, so they create a singleton that each method uses as an implicit parameter. But, this approach bites for the reasons above.

Try to never use a singleton, if you can. Although they may seem like a good approach from the start, it usually always leads to poor design and hard to maintain code down the line.

Are Singletons really that bad?

The key thing to remember is that design patterns are just a tool to help you understand the abstract concepts. Once you have that understanding, restricting yourself specifically to a "recipe" from a book is pointless and hurts your ability to write the code most appropriate for your purpose.

That said, reading books like GoF will present you with more ways to think about problems so that when the time comes to implement something on your own, you'll have a wider set of perspectives to approach the problem from.

In your case, if using singleton makes sense in every case, then go right ahead. If it "sort of" fits and you have to implement it in some clunky way, then you need to come up with a new solution. Forcing a pattern that isn't perfect is somewhat like hammering a square peg in a round hole.

Given that you say "this approach has been effective and proven very practical to our circumstances," I think you're doing fine.

Here are some good books:

Gang of Four Book - the classic book for design patterns

Head First Design Patterns - I've heard this recommended by a few people as an alternative

what is the advantage of Singleton Design Pattern

To assure only one and same instance of object every time.

Take a scenario, say for a Company application, there is only one CEO. If you want to create or access CEO object, you should return the same CEO object every time.

One more, after logging into an application, current user must return same object every time.

Are there any downsides to the singleton pattern?

From Wikipedia:

Some consider it an anti-pattern,
judging that it is overused,
introduces unnecessary limitations in
situations where a sole instance of a
class is not actually required, and
introduces global state into an
application.

Personally, since I've started using Spring to auto-wire my application I've never had the need to write a singleton.

When should the Singleton pattern NOT be used? (Besides the obvious)

Summary Version:

You know how often you use globals? Ok, now use Singletons EVEN LESS. Much less in fact. Almost never. They share all the problems globals have with hidden coupling (directly impacting testability and maintainability), and often the "only one can exist" restriction is actually a mistaken assumption.

Detailed Answer:

The most important thing to realize about a singleton is that it is global state. It is a pattern for exposing a single instance of globally unmitigated access. This has all of the problems in programming which globals have, but also adopts some interesting new implementation details and otherwise very little real value (or, indeed, it may come at an unnecessary extra cost with the single instance aspect). The implementation is different enough that people often mistake it for an object oriented encapsulation method when it is really just a fancy single instance global.

The only situation in which you should consider a singleton is when having more than one instance of already global data would actually be a logical or hardware access error. Even then you should typically not deal with the singleton directly, but instead provide a wrapper interface which is allowed to be instantiated as many times as you need it to be, but only accesses global state. In this manner you can continue to use dependency injection and if you can ever unmarry global state from the behavior of the class it isn't a sweeping change across your system.

There are subtle issues with this, however, when it appears as if you are not relying on global data, but you are. So that (using dependency injection of the interface which wraps the singleton) is only a suggestion and not a rule. In general it is still better because at least you can see that the class relies upon the singleton whereas just using the ::instance() function inside the belly of a class member function hides that dependency. It also allows you to extract classes relying on the global state and make better unit tests for them, and you can pass in mock do-nothing objects where if you bake reliance on the singleton directly into the class this is MUCH more difficult.

When baking a singleton ::instance call which also instantiates itself into a class you make inheritance impossible. Work-arounds typically break the "single instance" part of a singleton. Consider a situation where you have multiple projects relying on shared code in a NetworkManager class. Even if you want this NetworkManager to be global state, and single instance, you should be very skeptical about making it into a singleton. By creating a simple singleton which instantiates itself you are basically making it impossible for any other project to derive from that class.

Many consider the ServiceLocator to be an anti-pattern, however I believe it is a half step better than the Singleton and effectively eclipses the purpose of the Go4 pattern. There are many ways to implement a service locator, but the basic concept is that you break up the construction of the object and the access of the object into two steps. In this way, at runtime, you can connect the appropriate derived service, and then access it from a single global point of contact. This has the benefit of an explicit object construction order, and also allows you to derive from your base object. This is still bad for most of the stated reasons, but it is less bad than the Singleton and is a drop-in replacement.

One specific example of an acceptable singleton(read: servicelocator) may be in wrapping a single-instance c style interface like SDL_mixer. One example of a singleton often naively implemented where it probably shouldn't be is in a logging class (what happens when you want to log to console AND to disk? Or if you want to log subsystems separately.)

The most important problems of relying on global state, however, pretty much always come up when you're trying to implement proper unit testing (and you should be trying to do that). It becomes so much harder to deal with your application when the bowels of classes that you don't really have access to are trying to do unmitigated disk writing and reading, connect to live servers and send real data, or blast sound out of your speakers willy nilly. It's much, MUCH, better to use dependency injection so you can mock up a do-nothing class (and see that you need to do that in the class constructor) in case of a test plan and point it at that without having to divine all the global state your class depends on.

Related Links:

  • Brittleness invoked by Global State and Singletons
  • Dependency Injection to Avoid Singletons
  • Factories and Singletons

Pattern Use vs Emergence

Patterns are useful as ideas and terms, but unfortunately people seem to feel the need to "use" a pattern when really patterns are implemented as need dictates. Often the singleton specifically is shoehorned in simply because it's a commonly discussed pattern. Design your system with an awareness of patterns, but do not design your system specifically to bend to them just because they exist. They are useful conceptual tools, but just as you don't use every tool in the toolbox just because you can, you shouldn't do the same with patterns. Use them as needed and no more or less.

Example Single-Instance Service Locator

#include <iostream>
#include <assert.h>

class Service {
public:
static Service* Instance(){
return _instance;
}
static Service* Connect(){
assert(_instance == nullptr);
_instance = new Service();
}
virtual ~Service(){}

int GetData() const{
return i;
}
protected:
Service(){}
static Service* _instance;
int i = 0;
};

class ServiceDerived : public Service {
public:
static ServiceDerived* Instance(){
return dynamic_cast<ServiceDerived*>(_instance);
}
static ServiceDerived* Connect(){
assert(_instance == nullptr);
_instance = new ServiceDerived();
}
protected:
ServiceDerived(){i = 10;}
};

Service* Service::_instance = nullptr;

int main() {
//Swap which is Connected to test it out.
Service::Connect();
//ServiceDerived::Connect();
std::cout << Service::Instance()->GetData() << "\n" << ((ServiceDerived::Instance())? ServiceDerived::Instance()->GetData() :-1);
return 0;
}

Singleton anti-pattern

Stateful singletons are much more difficult to unit test.

I use stateless singletons which I don't see a problem with.

Since singletons can implement interfaces, they can be passed using dependency injection (and should be passed as such where possible)



Related Topics



Leave a reply



Submit