Singleton is a widely known design pattern that generally allows you to create a global object that can be accessed from anywhere in your application and it will assure that this object will be initiated only once per lifetime of your application/code.
Before digging into why such a pattern could cause lots of problems in your codebase let us first try and implement it and imagine a use case where it would fit.
How To Implement?
From its name a singleton is a single entity or object that would be created only once, how could we achieve something like that? how could we for example declare an object of type class A for example and disallow any other creations of instances of the same type?
Let us look at the code and discuss it further:
class Singleton {
private static instance: Singleton;
private constructor() {
}
static getInstance() {
if (!Singleton.instance) {
Singleton.instance = new Singleton();
}
return Singleton.instance;
}
// some other logic
}
let a = Singleton.getInstance();
let b = Singleton.getInstance();
// both a and b points at the same instance
What can we deduce here is that we have made our constructor a private function, meaning if we simply tried let c = new Singleton()
an error would occur as we can not access private methods in our class.
Another thing we did is we created a private static member of our Singleton type and then we create a public method that initiates our private static instance if it is not initiated and simply returns it. By doing that we assure that whenever we call the getInstance
function we will have the same instance in our codebase.
A Use Case
Where could we use something like this in our application? someone could purpose that if for example, we have an application that requires some kind of authentication we could make our User
object treated as a singleton so our whole application code could access it and manipulate it if needed.
class SingletonUser {
data: any;
private static instance: SingletonUser;
private constructor() {}
//...singleton logic
changeData(data) {
this.data = data;
}
// some other logic
}
By this, we could for example change the user's data when he logs in or logs out and so on.
Why Singletons Are Bad?
If we think about it for a second we now have our user's object globally initiated and any method or class in our codebase have an access to such object and could easily manipulate it, this could result in creating bugs and issues that are hard to maintain and find because you will have to figure out which part of your codebase changes or interacts with your singletons.
Another reason is that singletons increase coupling and decrease cohesion because if you want to change the behavior or extend its functionality you will have to change the class of the singleton.
The problem here arises when you have lots of areas that depend on your singleton and depend on its functionality, if somehow you needed to change the functionality of your singleton you will now be at risk that all of the areas that depended on it might crash or act in incorrect behavior.
Singletons also could cause you a nightmare when you are writing unit tests for your application. The idea behind unit testing is being able to test your functions/classes/modules without depending on other dependencies, when using singletons we will then have to initiate the correct shape for our singletons so that our methods/classes/modules would act correctly when under testing.
Singletons also violate the Single Responsibility Principle : In addition to their main responsibility, they are also responsible for implementing their own lifecycle.
When a class has multiple responsibilities "Like Singletons" it makes it harder to maintain and test, now you will need to test not only one responsibility but 2 and usually singletons carry lots of logic inside of them because they are being consumed through your whole application.
There are a lot of SOLID principles that Singletons violate like the Dependency Inversion Principle and Open / Closed Principle
Conclusion
Generally, I believe that Singletons have their own use cases but I would not recommend using them as Singletons are very much like the good things in life, they're not bad if used in moderation and through my coding career that never happened :D
Top comments (6)
Hello Sekab,
thanks for your article.
I enjoyed reading something understandable about software engineering for a change :)!
Regarding Singletons, I read in a book for game developers that it can be useful as a log file class to catch errors or the status of variables by writing them to a log file.
Nevertheless, I also read (I don't remember where) that singletons don't "work" with threads. So I agree with your statement "I believe that singletons and they have their own use cases".
Regarding the Open/Closed principle, I'm not entirely sure if that's true, because doesn't it depend on how you implement your singleton?
I also don't see how the Dependancy Inversion Principle is generally violated here, because doesn't that depend on how the relationships between your classes are structured, e.g. in the UML class diagram?
Thanks a lot for your reply :D
Actually there is a workaround on how to create singletons on multithreaded environments, you can change the
getInstance
function to be synchronized so multiple threaeds wont access it simultaneously.The Dependency Inversion Principle states that the high-level policy of your system should not depend on low-level details. Also, abstractions should never depend on details. When we generally create singletons we attempt to write a global object that encapsulates the low-detail logic instead of the high-level business logic.
Also in the Open/Closed principle whenever you want to change the behaviour of the singleton you will have to change the class itself, lets take an example.
Say your singleton was a class that calculates the areas of multiple shapes ( Square / Rectangle )
If for example you needed to add a newer shape to your calculations you will now modify the
calculate
function inside your singleton.This is a fairly simple case but you could think about other usecases in that matter and I could somehow agree that it does not violate the Dependency Inversion Principle in its design but in most codebases that is used in it does.
Singletons do not violate SRP except when poorly designed. They are a perfect pattern when needed. The are used to obtain adressibility, to an object often with functions,methods or properties pertaining to the object name which describes the responsibility.
There are other patterns which work as well, in particular events and event handlers. If the event definition is static then the ability is similar to a singleton.
In Javascript, the function, a true first class citizen which diminishes the need for singletons.
Finally, observables which are extensions of the event pattern may be static too. Event bus design often use this pub/sub pattern also diminishing the need for the singleton
All work, all are good so design wisely and there won't be any issues.
I totally agree with you, they could be perfect in such use cases but I generally would not recommend the using of such pattern. It just doesn't feel right to have something globally swimming in your codebase and you'd have to design it carefully to take care of your unit tests and to disallow other functions or classes to manipulate it without being authorized to.
Singletons are great if you are using Dependency Injection. JavaScript sucks at DI, so yeah don't use them with JS. Other truly Object Oriented languages such as Java, C#, and even PHP can benefit from from singletons with DI because they are injected as needed. The default for most DI libraries to use singletons. There are times when you want to instantiate non-singletons in a DI situation. Singletons are not a wholesale always bad as many things it IT, it depends
The way I understand Dependency injection is that you have an injection pool ( map of classes that you would inject ) and the injector injects such classes from its pool whenever its needed. They are not singletons by nature they are normal classes that gets injected, I'm not certian if this is the case in C# because I normally don't use it.
There are lots of implementations of dependency injection but in most of them it allows you to inject an instance of a class more than once ( meaning there will be more than one instance not a single one ) this indicates that simple DI does not inject singletons. This is how for example Angular implements it