Title: Design Mode – Singleton Mode date: 04-01

  • design

Recently looked at the vUE source code, is really a face of mengbi, put me as a philosopher, the brain is always “where AM I” “who am I”, “WHAT AM I doing” philosophy three even reverberated, listen to a friend recommended to look at the design mode first, and then look at the VUE source code, there will be a clear feeling of clearing the clouds. Abandoned the vue source code, ready to look at the design pattern. Of course, we looked at the simplest singleton pattern first.

The singleton pattern

What is the singleton pattern? Ensure that a class has only one instance and provide its global access point. The singleton pattern is a common pattern. There are some objects that we usually need only one, such as thread pool, global cache, browser window object, and so on. Singletons are also widely used in javascript development. Imagine that when we click on the login button, a single popover pops up on the page. This popover is unique and is always created once no matter how many times we click on it. Of course, some people say that you don’t need the singleton mode, when you click again, remove the previous popover. In some cases, if remove is added, there will be a blank flash and the DOM will be redrawn and redrawn. In general, it is better to use the singleton pattern.

To implement the singleton

Implementing a singleton pattern is not complicated. It simply uses a variable to indicate whether the current class has already created an object, and if so, the next time the object is created, the previous object is returned.

var singleTon = function(name) { this.name = name; this.instance = null; } singleTon.prototype.getName = function(){ console.log(this.name) } singleTon.getInstance = function(name){ if(! this.instance) { this.instance = new singleTon(name) } return this.instance; } var singleTon = function(name) {this.name = name; } singleTon.prototype.getName = function(){ console.log(this.name) } singleTon.getInstance = (function(){ var instance =  null; return function(name){ if(! instance) { instance = new sinleTon(name); } return instance; Var a = singleton.getinstance ('first'); var b = singleTon.getInstance('second'); console.log(a === b) //true; a.getName() //first b.getName() //firstCopy the code

We get the unique object of the singleTon class by singleton.getInstance, which is relatively simple. There is a problem, however, with the added opacity of the class. Users of the singleTon class must know that this is a singleTon class, unlike new XXX, which uses singleTon to fetch objects.

Transparent singleton pattern

Our goal is to achieve a “transparent” singleton class that users can use to create objects just like any other normal class. In the following example, we will use the createDiv singleton class, which creates a unique div on the page;

    var CreateDiv = (function(){
        var instance = null;
        var CreateDiv = function(html) {
            if(instance) {
                return instance;

            }
            this.html = html;
            this.init()
            return instance = this;
        }
        CreateDiv.prototype.init = function(){
            var div = document.createElement('div');
            div.innerHTML = this.html;
            document.body.appendChild(div)
        }
        return createDiv
    })()

    var a = new CreateDiv('first');
    var b = new CreateDiv('second');
    console.log(a === b) //true
Copy the code

A transparent singleton class is now complete, but it also has some disadvantages. Using self-executing anonymous functions and closures to wrap instance, and having the closure return the constructor of the real SingleTon, adds complexity to the program and makes reading uncomfortable. Look at the current SingleTon constructor.

    var CreateDiv = function(html) {
        if(instance) {
            return instance;
        }
        this.html = html;
        this.init();
        return instance = this;
    }
Copy the code

In this code, the CreateDiv constructor actually does two things. The first is to create the object and perform the initialization method init(). The second is to ensure that there is only one object. While I haven’t touched on the concept of the single responsibility principle yet, it is clear that this is a bad idea, to say the least, because constructors look strange. If one day we needed to use this class to create thousands of divs on a page, that is, to change the class from a singleton to a class that can create multiple instances, we would have to rewrite the constructor CreateDIv to remove the section that controls the creation of a unique object, which would cause me unnecessary trouble.

Implement the singleton pattern with a proxy.

We solve the above problems by introducing agents. We still use the CreateDiv constructor to remove the code responsible for managing the singleton.

var CreateDiv = function(html){
    this.html = html;
    this.init()
}
CreateDiv.prototype.init = function(){
    var dom = document.createElement('div'); div.innerHTML = this.html; dom.body.appendChild(div); } Next, introduce the proxy class. proxySingleTonCreateDiv: var proxySingleTonCreateDiv =function(){
    var instance;
    return function(html) {
        if(! instance){ instance = new CreateDiv(html) }return instance
    }
}
var a = new proxySingleTonCreateDiv('first');
var b = new proxySingleTonCreateDiv('second')
console.log(a === b);
Copy the code

We also write a singleton pattern by introducing the proxy class, but now we move the logic responsible for managing the singleton pattern to proxySingleTonCreateDiv. This makes CreateDiv a generic class, which is combined with proxySingleTonCreateDiv to achieve the singleton class pattern.

Inert singleton

Now that you’ve seen some implementations of singletons, this section looks at lazy singletons. Lazy singletons are instances of objects that are created only when needed. Lazy singletons are the focus of the singleton pattern, which is very useful in practical development. Useful chengdu may be more than we think. In fact, this technique was used at the beginning of this chapter. Instance instances are always created when we call singleton.getInstance, not when the page home is in good condition, as follows:

    singleTon.getInstance = (function(){
        var instance = null;
        return function(name) {
            if(! instance) { instance = new singleTon(name) }return instance;
        }
    })()
Copy the code

Suppose we are WebQQ developers. When we click on the QQ avatar in the middle, a login popup will pop up. Obviously, this popup page is always unique and two Windows cannot appear at the same time.

The first is that when the page is initialized, the div is created, and the popover must be hidden until the user clicks login.

<html>
 <body>
       <button id="loginBtn"</button> </body> <script> var loginLayer = (function(){
       var div = document.createElement('div');
       div.innerHTML = 'I'm landing popover';
       div.style.display = 'none';
       document.body.appendChild('div')
       return div
   })()
   documengt.getElementById('loginBtn').onclick = function(){
       loginLayer.style.display = 'block'
   }
</script>
</html>
Copy the code

There’s a problem with this approach. Maybe we go into webQQ just to play games or look at the weather, do not need to log in operation. However, the login popover is always created in the first place, so it is possible to waste some DOM performance.

    <html>
        <body>
            <button id="loginBtn"</button> <script> var loginLayer =function(){
                    var dom = document.createElement('div');
                    dom.innerHTML = 'I'm landing popover';
                    dom.style.display = 'none';
                    document.body.appendChild('dom');
                    return dom
                }
                document.getElementById('loginBtn').onclick = function(){
                    var createLayer = loginLayer();
                    createLayer.style.display = 'block';
                }
            </script>
        <body>
    </html>
Copy the code

The effect of singletons is now lost, although the purpose of inertia is achieved. When we click login, a new login popover will appear. Although it is possible to remove the float window from the page by clicking the close button on the float window (which is not done here), this frequent creation and deletion of nodes is clearly not reasonable, and frequently redraws and reflows of the DOM are not necessary. In this case, we can use a variable to determine whether a popover has been created, as we did in the first section.

    <html>
        <body>
        <button id="loginBtn"<script> var loginLayer = (function(){
              var div = null;
              return function(html){
                  if(! div) { div = document.createElement('div');
                    div.innerHTML = html;
                    div.style.display = "none";
                    document.body.appendChild(div);
                  }
                  return div
              }
          })();
          document.getElementById('loginBtn').onclick = function(){
              loginLayer('I'm landing popover').style.display = "block"
          }
        <script>
        </body>
        
     </html>
Copy the code

Here’s a little trick to tell if the DOM has been redrawn or reflowed. Start by opening Chrome devTools and clicking on the three-point symbol in the upper right corner. Then click On More Tools and click on Rendering.

Attach the Paint Flashing hook.

When you click the login button for the first time, a green box will appear, indicating that the DOM has been redrawn and reflowed. When you click the button again, a green box will not appear.

The singleton pattern is a very simple and practical pattern, especially the lazy singleton technique, where objects are created when appropriate and only one object is created. More intriguingly, the responsibility for creating objects and managing singletons is distributed among different methods, and it is these two methods combined that have the power of the singleton pattern.