113 lines
		
	
	
	
		
			2.9 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			113 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;
							 | 
						||
| 
								 | 
							
								```
							 |