Hello folks! How long has it been since I wrote an article?
So I have the idea to create a several articles exploring design patterns using typescript based on GoF.
In this article I will talk about the first Creational Design Pattern, called Singleton
The Singleton Pattern ensure that a class has only one instance and provide a global access point for it.
So we have a global access of the Singleton of all entire application. Also, we can protect the instance with encapsulation, avoiding the override of the value.
So we have an instance
that is a private attribute. On this class diagram it's represents as singleObj
.
And we have a private constructor
and we have the method called getInstance
to get the instance of the class.
Imagine that we have an access to the some Database, so for each operation in your operation you need open a new connection to your DB. Sooo, it's a bad idea, don't agree?
We will create a lot of connections for each operation and we will overload our database.
In this case we can use the Singleton! So we can create an unique instace for our entire application, that will be initialized and we will get instance of the connectinon only one time. If the instace is not created we create a new instance, if the same instance is already created we will just use the method getInstance
.
Let's create a example, for this I will create a index.ts
with the Singleton Example:
export class MyDatabase {
private static instance: MyDatabase;
private constructor() {}
static getInstance(): MyDatabase {
if (MyDatabase.instance === undefined) {
MyDatabase.instance = new MyDatabase();
}
return MyDatabase.instance;
}
}
Notice that we have the instance
and the contructor
are privates and to get the instance, we need to call the getInstance()
of our database.
Now let's add some fake data on memory of users in our Singleton class:
export interface User {
id: number;
name: string;
}
export class MyDatabase {
private static instance: MyDatabase;
private users: User[] = [];
private constructor() {}
static getInstance(): MyDatabase {
if (MyDatabase.instance === undefined) {
MyDatabase.instance = new MyDatabase();
}
return MyDatabase.instance;
}
addUser(user: User) {
this.users = [...this.users, user];
}
displayUsers(): void {
console.log(this.users);
}
}
Now we have users, and we can add and display the users in our singleton class.
Before, let's see if the instance created is the same. For that, I will create another file called useSingleton.ts
:
import { MyDatabase } from ".";
const myDb = MyDatabase.getInstance();
const myDb2 = MyDatabase.getInstance();
console.log(myDb === myDb2);
The output will be:
true
Because, we created the instance of MyDatabase on the first variable myDb
and the myDb2
will use the same instace created.
And to use the methods of the singleton class just use:
import { MyDatabase } from ".";
const myDb = MyDatabase.getInstance();
myDb.addUser({ id: 1, name: "kevin" });
myDb.addUser({ id: 2, name: "uehara" });
myDb.displayUsers();
The output will be:
[ { id: 1, name: 'kevin' }, { id: 2, name: 'uehara' } ]
Trade-offs
Good:
- Access controlled thanks to encapsulation by unique instance
- Use
lazy instanciation
, so the singletion is created only the use moment - Allow to use on entire project and avoid multiple instantiations.
Bad:
- Sometimes is hard to test
- Violates the Principe of Single Responsability of Solid
- Requires special treatment in cases of concurrency
So that's it people! I hope that this simple article may help help you to understand the Singleton Design pattern.
Thank you so much, to read until here!
Contacts:
Email: uehara.kevin@gmail.com
Linkedin: https://www.linkedin.com/in/kevin-uehara
Youtube: https://www.youtube.com/@ueharakevin/
Instagram: https://www.instagram.com/uehara_kevin/
Twitter: https://twitter.com/ueharaDev
Github: https://github.com/kevinuehara
dev.to: https://dev.to/kevin-uehara
Top comments (0)