The Singleton Pattern: To be or not to be [used]?

Started by
79 comments, last by 21st Century Moose 11 years, 5 months ago

If a car has one (1) steering wheel it does not mean that the car has an arbritary number of steering wheels, or that it sometimes has one steering wheel - it always has one steering wheel.


Exactly. It does not mean there is only one steering wheel in the entire universe, which is what a singleton enforces.
Advertisement

[quote name='trasseltass' timestamp='1352400093' post='4998968']
If a car has one (1) steering wheel it does not mean that the car has an arbritary number of steering wheels, or that it sometimes has one steering wheel - it always has one steering wheel.


Exactly. It does not mean there is only one steering wheel in the entire universe, which is what a singleton enforces.
[/quote]

If you are designing a universe I could see how that would be true. If your "system of interest" is a bit smaller, for example a car, it perhaps only exists one steering wheel.

If a car has one (1) steering wheel it does not mean that the car has an arbritary number of steering wheels, or that it sometimes has one steering wheel - it always has one steering wheel.

But how many cars are there? For there to only ever be one steering wheel, there would also have to only ever be one car.

Your UML scenario indicates that there may be many-to-1 relations between objects. It in no way implies that there may ever be absolute many-to-1 relations.

I'm not saying that the singleton pattern is for everyone, just that it solves the design problem of encapsulating a single object instance.[/quote]
The "design problem of encapsulating a single object instance" is exactly that, a design problem.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]


IMO there's only one "rule of thumb" you need to know: Everything that can be implemented without the singleton pattern, should be implemented without the singleton pattern.


I can think of four reasons where this may not hold true. I don't say that the following 4 cases always are true, just that there are situations where they are true.

  1. Doing an implementation for a thing that there must be only one of in such a way that the design allows for multiple future extensions takes more effort. Usually you have a limited budget, and the singleton pattern is very quick and easy to implement. The designer of the code maybe just isn't experienced enough, and as a project leader you sometimes have to accept something that works, even if it is not optimal.
  2. Testing the general purpose variant of the design may take more effort. (Yes, I know, using global instances of a singleton may also add to the testing effort, but the discussion about singletons is not the misuse of global objects).
  3. A generalized class can cost more CPU time. I am not saying it will, or that it really matters, just that it may be the case.
  4. The factory pattern is based on the singleton pattern. That is, it usually uses classes with a private constructor to force clients to use the factory methods.
[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/
> But how many cars are there? For there to only ever be one steering wheel, there would also have to only ever be one car.

Sorry, I forgot to mention that the system of interest in this example is the car. We're designing a single car and eventually the goal is to deliver instances of this car, maybe in larger numbers. We're not designing and delivering a composite of multiple cars. smile.png

Doing an implementation for a thing that there must be only one of in such a way that the design allows for multiple future extensions takes more effort. Usually you have a limited budget, and the singleton pattern is very quick and easy to implement.

A global is even quicker and easier to implement, and is arguably less objectionable. Passing in a pointer to an instance is barely more complicated.

Testing the general purpose variant of the design may take more effort. (Yes, I know, using global instances of a singleton may also add to the testing effort, but the discussion about singletons is not the misuse of global objects).[/quote]
Singletons (and globals in general) are the anathema of testing. Anytime a class calls to a global, they escape your test harness., and you are screwed.

A generalized class can cost more CPU time. I am not saying it will, or that it really matters, just that it may be the case.[/quote]
Artificially restricting the use-cases of a class to a single instance is the path that requires additional effort here. Not enforcing those constraints is free.

The factory pattern is based on the singleton pattern. That is, it usually uses classes with a private constructor to force clients to use the factory methods.[/quote]
No, just, no. If your factories are singletons, then you are doing that wrong too.

What happens when you need to dynamically replace a factory at runtime, or any of a dozen more trivial use-cases?

We're not designing and delivering a composite of multiple cars.

And when you need to instantiate multiple cars in your test harness, what then? Try telling an automotive engineer that he is designing a car of which only a single will ever be built, and no prototypes either...

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

We're not designing and delivering a composite of multiple cars.

And when you need to instantiate multiple cars in your test harness, what then? Try telling an automotive engineer that he is designing a car of which only a single will ever be built, and no prototypes either...

If your test subject for a black box test is the entire system, e.g. the car, in what situation would you need to create multiple instances of it? Sounds like something that is dependant on the design of your test harness / test environment. I think you're confusing design with production - it should be perfectly fine to design a single system and then produce multiple instances of it.
I don't have any more time for this, but it's always nice to discuss Singletons. Lots of strong opinions. :)

TBH, I never use singletons for game development. I have however seen it used for embedded software projects that are strongly linked to using UML.
I am still definitely on the side of "singletons are evil" but less so than I used to be.


Avoiding globals and singletons can lead to a lot of unnecessary upfront design work. "You might need more than one down the road" is the same rhetoric that justifies layers and layers of abstraction. "But I need to make it extensible for the future!" You don't know what the requirements will be in the future. Don't waste time over-designing something that will never be used.

Another thing I've discovered is that global functions and global state are two entirely different things. I used to try to minimize dependencies by not using global functions, but really those are totally fine. It's global state that's more dangerous.

It's global state that's more dangerous.

One could argue that it's the 'state' that is dangerous, rather than the 'global' part of it.

Stateless systems are far easier to test and prove correctness of, after all.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

This topic is closed to new replies.

Advertisement