The concept of singleton patterns

Singleton is a very common but very simple design pattern. It means that there can only be one instance object in a class. Even if the class is instantiated several times, only the instance object after the first instance of the class is returned. The singleton mode can reduce unnecessary memory overhead, save memory space, and improve performance.

Many times the whole system only needs to have one global object, which helps us coordinate the behavior of the whole system. For example, in a server program, the configuration information of the server is stored in a file. The configuration data is read by a singleton and then retrieved by other objects in the server process. This approach simplifies configuration management in complex environments.

Singleton pattern thinking

In code development, a class with only one instance object is called a singleton. So how do you guarantee that a class can only have one object?

We know that in object-oriented thinking, objects can be created through the constructor of a class, as long as there is enough memory to create any object.

So if you want to limit a class to a single singleton, you need to work on its constructor.

So the idea of implementing the object singleton pattern is:

A class can return a reference to an object (always the same) and a method that gets the instance (it must be a static method, usually named getInstance).

2. When we call this method, we return the reference held by the class if it is not empty. If the reference held by the class is empty, we create an instance of the class and assign its reference to the reference held by the class.

3. We also define the constructor of the class as a private method, so that code elsewhere cannot instantiate objects of the class by calling the constructor of the class. Only static methods provided by the class can get a unique instance of the class.

The case where the singleton pattern is not used

Instantiate A class A to create A memory space p1

Instantiating class A again opens up another memory space, P2

As many times as you instantiate, you open up as much memory

The case with the singleton pattern

Instantiate A class A to create A memory space p1

Instantiate class A again to get A memory space, but get the memory space p1 created by the first instantiation of the class

No matter how many times the same class is instantiated, only the object instantiated the first time is returned

Advantages of the singleton pattern

  1. In the singleton pattern, there is only one instance of an active singleton, and all instantiations of a singleton class yield the same instance. This prevents other objects from instantiating it and ensures that all objects have access to an instance
  2. The singleton pattern is scalable in that the class itself controls the instantiation process, and the class is scalable in changing the instantiation process.
  3. Provides controlled access to a unique instance.
  4. Since there is only one object in system memory, system resources are saved, and the singleton pattern can certainly improve system performance when objects are frequently created and destroyed.
  5. A variable number of instances is allowed.
  6. Avoid multiple occupancy of shared resources.

Disadvantages of the singleton pattern

  1. This does not apply to changing objects, and if objects of the same type are always changing in different use case scenarios, singletons will cause errors in the data and will not save each other’s state.
  2. Because there is no abstraction layer in the simple interest pattern, it is very difficult to extend singleton classes.
  3. Singleton classes are too heavy on responsibilities and violate the “single responsibility principle” to some extent.
  4. Abuse of singletons will bring some negative problems, for example, in order to save resources, the database connection pool object is designed as a singleton class, may lead to too many programs sharing the connection pool object and the connection pool overflow; If an instantiated object is not used for a long time, the system considers it garbage and collects it, resulting in a loss of object state.

Application scenarios of the singleton mode

The singleton pattern allows only one object to be created, thus saving memory and speeding up object access. Therefore, objects need to be suitable for use in common situations, such as multiple modules using the same data source to connect objects, and so on. Such as:

Objects that need to be frequently instantiated and then destroyed.

2. Objects that take too much time or resources to create, but are often used.

Stateful tool class objects. Objects that frequently access databases or files.

The following are typical usage scenarios for the singleton pattern:

In the case of resource sharing, avoid performance or loss caused by resource operations. A database connection pool, for example, is usually designed in a singleton pattern because a database connection is a database resource. The use of database connection pool in database software system is mainly to save the efficiency loss caused by opening or closing the database connection. This efficiency loss is very expensive, and the use of singleton mode to maintain, can greatly reduce this loss.

Facilitates communication between resources in the case of resource control. For example, thread pool, the design of multi-threaded thread pool is also generally adopted singleton mode, this is because the thread pool is convenient to control the threads in the pool.

Here is a simulation of ES5 without the singleton pattern:

    function Demo(){
        this.name = "remi"
        this.age = 18
        this.sex = "A strong grown man."
    }

    var remi = new Demo() // Instantiate the constructor to get an object
    console.log(remi.name)

    var tongtong = new Demo() // Instantiate the constructor to get another object
    console.log(tongtong.name)

    console.log(remi === tongtong) // It must be false, two completely different objects

Copy the code

Here is a simulation of using the singleton pattern in ES5:

// Static properties and methods do not need new
    function Demo(name){
        // demo. unique === undefined; If it is not instantiated for the first time, demo. unique will have a value equal to the instantiated object this, not undefined
        if(Demo.unique ! = =undefined) {// if it is not congruent with undefined, it is not the first instantiation
            return Demo.unique // Return the object after the first instantiation
        }

        // if this is the first instantiation, demo. unique is undefined
        this.name = name
        this.age = 18
        this.sex = "boy"

        // Add a unique static attribute and assign the unique attribute to the object this after the first instantiation, which will be used for each subsequent instantiation
        Demo.unique = this // This represents the instantiated object
    }

    var remi = new Demo("remi") // Instantiate the constructor to get an object
    console.log(remi.name)

    var tongtong = new Demo("tongtong") // Instantiate the constructor to get the same object
    console.log(tongtong.name)

    console.log(remi === tongtong) // It must be true. Both instances are the same
Copy the code

Here is a simulation of using the singleton pattern in ES6:

    class Demo{
        constructor(){
            this.name = "remi"
        }

        // Static method, get singleton mode
        static getInstance(){
            if(!this.instance){ // this. Instance is an attribute of its own creation, which must be undefined, and true if it is the other way around
                this.instance = new Demo() // Assign this.instance to the object that instantiates the class
            }
            return this.instance // return this.instance, undefined for the first time, enter if judgment, instantiate the class Demo, get the object instantiated for the first time
            // Each time we instantiate Demo of this class, this.instance has a value, which is the object after the first instantiation, so we do not enter if judgment, and return the object after the first instantiation}}let Remi = Demo.getInstance() Instantiate and call the singleton static method for the first time
    let TongTong = Demo.getInstance() Instantiate and call the singleton static method a second time
    console.log(Remi === TongTong) // true

    let Remi1 = new Demo() // If the singleton method is not called, the generated singleton object is not a singleton
    let TongTong1 = new Demo()
    console.log(Remi1 === TongTong1) // false
Copy the code