This article is summarized by our team Chen Jiahui

The singleton pattern is one of the most common design patterns. In the actual development, we only need one object in the system, such as thread pool, database operation object, global cache, and so on, at this time I will use the singleton pattern.

define

The singleton pattern is defined by ensuring that a class has only one instance and provides a global access point to access it. The UML diagram is as follows:

The Singleton pattern contains only one role, the Singleton class. The singleton class has a private constructor that ensures that users cannot instantiate it directly with the new keyword. In addition, the pattern contains a static private member variable and a statically public factory method that checks for the existence of the instance and instantiates itself, then stores it in the static member variable to ensure that only one instance is created.

implementation

ES5 writing

Var Singleton = function(name) {this.name = name; Singleton.getinstance = function(name) {// Create an instance of the class if(! This.instance) {this.instance = new Singleton(name)} Return this.instance} var a = singleton.getInstance ('sven1') var b = singleton.getInstance ('sven2') Console. log(a === b) // outputs true console.log(a) // outputs Singleton {name: "sven1", instance: Singleton {name: "sven1", instance: null} console.log(b)Copy the code

ES6 writing

Class Singleton {constructor(name) {this.name = name this.instance = null} Static getInstance(name) {if(! this.instance) { this.instance = new Singleton(name) } return this.instance } } var a = Singleton.getInstance('sven1') Var b = Singleton. GetInstance ('sven2') console.log(a === b) true console.log(a) Singleton {name: "sven1", instance: null} console.log(b)Copy the code

When we call the static public method getInstance twice, we return the same object, thus achieving our goal of ensuring only one instance of a class.

I’m sure you all have the same question as I do after looking at this code, which is that the name property of a and b is sven1, which is expected, but the instance property is null, which is not. New Singleton(name) is assigned to this.instance in the getInstance static method. We might as well print this in the constructor and this in the static method getInstance

Singleton {name: "sven1", instance: null}} function(name) {this.name = name; // a flag to determine whether instances of the class have been created this.instance = null; console.log(`constructor:${Singleton}`) }Copy the code

This in the constructor refers to the object of the current class, whereas this in the static method getInstance refers to the static method.

vulnerability

Although the objects we get from the static factory methods of this class are the same object, remember that one of the necessary conditions for a singleton class we introduced in the beginning is a private constructor. Why have such a condition? If the user’s first response to a class is “new”, then the static factory method getInstance does not work. Let’s verify this:

var a = Singleton.getInstance('sven1') var b = Singleton.getInstance('sven2') var c = new Singleton('sven3') Console. log(a === b) // outputs true console.log(a) // outputs Singleton {name: "sven1", instance: Null} console.log(b) // output Singleton {name: "sven1", instance: Null} console.log(a === c) // output false console.log(c) // output Singleton {name: "sven3", instance: null}Copy the code

The object c generated by new is not the same object as the object (a, b) obtained by the static factory method getInstance, so this singleton pattern is not sufficiently “singleton”.

perfect

I haven’t found a way to make constructors private in JavaScript yet, so we need to fix the “hole” in constructors.

A class must have a constructor method. If a class does not explicitly define a constructor, an empty Constructor method is automatically added to the class

ES5 writing

var Singleton = function(name) { if (! Singleton.instance) {this.name = name // a token, Singleton.instance = this} return singleton. instance} // provides a static method, Singleton.getinstance = function(name) {// Create an instance of the class if(! This.instance) {this.instance = new Singleton(name)} Return this.instance} var a = singleton.getInstance ('sven1') var b = singleton.getInstance ('sven2') var c = new Singleton('sven3') console.log(a === b) true console.log(a) "Sven1 "} console.log(b) // Singleton {name: "Sven1 "} console.log(a === c) // outputs true console.log(c) // outputs Singleton {name: "sven1"}Copy the code

ES6 writing

class Singleton { constructor(name) { if (! Singleton.instance) {this.name = name // a token, Singleton.instance = this} return singleton. instance} // create a well-known interface, Static getInstance(name) {if(! this.instance) { this.instance = new Singleton(name) } return this.instance } } var a = Singleton.getInstance('sven1') Var b = singleton.getInstance ('sven2') var c = new Singleton('sven3') console.log(a === b) // Output true console.log(a) // Singleton {name: "sven1"} console.log(b) "Sven1 "} console.log(a === c) // outputs true console.log(c) // outputs Singleton {name: "sven1"}Copy the code

By adding a similar judgment to the constructor, the “hole” is closed.