eolas/neuron/7aecb0c4-f9f9-4579-9564-8a4cb5e9c958/Singleton_pattern.md
2025-03-14 17:01:58 +00:00

112 lines
2.9 KiB
Markdown

---
tags:
- OOP
- design-patterns
---
# Singleton pattern
As the name suggests, the Singleton pattern is best used in scenarios where you
only want to use a single, unique instance of a class. This is for functionality
that should only be executed once in the lifecycle of an application. The
canonical case would be some kind of bootstrapping process required at
initialisation, or initial configuration for an app.
## Use-cases
- Establishing connection to backend database
- API connection (managing tokens so that you are not sending multiple
unnecessary calls)
- Configuration settings for an app
- Global state stores in Redux and the React Context API
> With this pattern only one instance of the class can exist. If no instance of
> the singleton class exists then a new instance is created and returned, but if
> an instance already exists, then the reference to the existing instance is
> returned. A singleton should be immutable by the consuming code, and there
> should be no danger of instantiating more than one of them.
## Implementation
This pattern can be implemented either with a object or a class.
In the example below, a global store for a modern JS application is created
using an object.
### Using an object
We ensure singularity by:
- using `const` for the object so that it cannot be reassigned
- using `Object.freeze` so that the fields cannot be overwritten, deleted, or
additional fields added
```js
const _data = [];
// Methods to add and retrieve data from the store
const UserStore = {
add: (item) => _data.push(item),
get: (id) => _data.find((d) => d.id === id),
};
Object.freeze(UserStore);
export default UserStore;
```
### Using a class
The same process can be created using classes:
```js
class UserStore {
constructor() {
this._data = [];
}
add(item) {
this._data.push(item);
}
get(id) {
return this._data.find((d) => d.id === id);
}
}
const instance = new UserStore();
Object.freeze(instance);
export default instance;
```
Bear in mind that this is really just an ES6 module with `freeze` applied. The
only real difference between a singleton and a module is that there should only
be one instance of it.
With classes, there is a further step that can be taken to prevent more than
once instance of the class being created. This is necessary if you want to be
really strict because it is of course possible for a well motivated person to
get around the safeguards we established above. We do this by having the class
itself check whether there is already an instance of itself. If so, it just
returns the already existing instance. We do this by using the self-reference
inherent in `this` :
```jsx
class UserStore {
constructor() {
if (!UserStore.instance) {
this._data = [];
UserStore.instance = this;
}
return UserStore.instance;
}
//rest is the same code as preceding example
}
const instance = new UserStore();
Object.freeze(instance);
export default instance;
```