最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 『面试的底气』—— 设计模式之单例模式|8月更文挑战

    正文概述 掘金(红尘炼心)   2021-08-08   424

    这是我参与8月更文挑战的第7天,活动详情查看:8月更文挑战

    前言

    在面试高级前端时,往往会遇到一些关于设计模式的问题,每次都回答不太理想。恰逢8月更文挑战的活动,准备用一个月时间好好理一下关于设计模式方面的知识点,给自己增加点面试的底气。

    在往期几篇文章中详细介绍了设计模式的六大原则:

    • 『面试的底气』—— 设计模式之单一职责原则|8月更文挑战
    • 『面试的底气』—— 设计模式之开放封闭原则|8月更文挑战
    • 『面试的底气』—— 设计模式之最少知识原则|8月更文挑战
    • 『面试的底气』—— 设计模式之里氏代换原则|8月更文挑战
    • 『面试的底气』—— 设计模式之依赖倒置原则|8月更文挑战
    • 『面试的底气』—— 设计模式之接口隔离原则|8月更文挑战

    接下来一起学习和实践设计模式之单例模式,在实践过程中要严格遵循六大原则,哪个原则不太熟悉,可以访问上面对应的链接。

    定义

    单例模式,保证一个类仅有一个实例,并提供一个访问它的全局访问点。

    自己的理解

    通常我们可以让一个全局变量使得一个对象被访问,但它不能防止实例化多个对象。一个最好的办法就是,让类自身负责保持它的唯一实例,且这个类保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

    实现单例模式

    要实现一个简单的单例模式并不复杂,无非是用一个变量来缓存一个类实例化生成的对象,然后用这个变量来判断一个类是否已经实例化过。如何变量有值,则在下一次要获取该类的实例化生成的对象时,直接返回这个变量(之前实例化生成的对象)。

    var Singleton = function(name) {
        this.name = name;
        this.instance = null;
    };
    Singleton.prototype.init = function() {
       //...初始化
    };
    Singleton.getInstance = function(name) {
        if (!this.instance) {
            this.instance = new Singleton(name);
            this.instance.init();
        }
        return this.instance;
    };
    var a = Singleton.getInstance('a');
    var b = Singleton.getInstance('b');
    console.log(a === b); // true
    

    正常来说一个类每次实例化生成的对象是不同的,在上述代码中分别使用Singleton.getInstance获取Singleton类实例化生成的对象并赋值给对象a和对象b,执行console.log(a === b)打印出true,说明上述代码实现单例模式成功。

    或不把实例化生成的对象挂载到类的属性上也可以实现,代码如下所示:

    var Sington = function( name ){
     this.name = name;
    };
    Singleton.prototype.init = function() {
       //...初始化
    };
    Singleton.getInstance = (function(){
     var instance = null;
     return function( name ){
     if ( !instance ){
       instance = new Singleton( name );
       instance.init();
     }
     return instance;
     }
    })(); 
    

    变量instance用来缓存类实例化生成的对象,用自执行匿名函数创建了一个闭包,把变量instance存储在闭包中,每次执行Singleton.getInstance时就可以用变量instance来判断Singleton类是否已经实例化过。

    透明的单例模式

    上述实现单例模式的方法中有一个问题,就是增加了这个类的“不透明性”,Singleton类的使用者必须知道这是一个单例类,跟以往通过new XXX的方式来实例化类,这里要使用Singleton.getInstance来实例类。故要换一种方法来实现透明的单例模式。

    const Singleton = (function() {
        let instance;
        const Singleton = function(name) {
            if (instance) {
                return instance;
            }
            this.name = name;
            this.init();
            return instance = this;
        };
        Singleton.prototype.init = function() {
            //...初始化
        };
        return Singleton;
    })();
    const a = new Singleton('a');
    const b = new Singleton('b');
    console.log(a === b); // true
    
    

    以上代码中,Singleton类的构造函数是一个自执行的匿名函数,会构成一个闭包,可以把判断类是否实例化过的和缓存类实例化生成的对象的变量instance缓存起来,最后在返回真正的Singleton类构造方法。那么就可以使用new Singleton来实例化Singleton类。

    必须遵循设计模式的原则

    上述代码还不够完美,有两点:

    • Singleton类的真正的构造函数放在自执行的匿名函数中返回,有点奇怪。

    • Singleton类的构造函数中违背了设计模式的单一职责原则,做了二件事情,创建类实例化生成的对象和执行初始化init方法,保证了只能实例化一次。

    实现任何设计模式都要遵循设计模式的原则,要把“创建类实例化生成的对象和执行初始化init方法”和“保证了只能实例化一次”这两个职责分隔开来。下面用代理实现单例模式。

    const Singleton = function (name) {
      this.name = name;
      this.init();
    }
    Singleton.prototype.init = function () {
      //...初始化
    };
    const PropxSingleton = (function () {
      var instance;
      return function (name) {
        if (!instance) {
          instance = new Singleton(name);
        }
        return instance;
      }
    })();
    var a = new PropxSingleton('a');
    var b = new PropxSingleton('b');
    console.log(a === b);//true
    

    以上用代理类propxSingleton实现了Singleton类的单例模式,而Singleton类仍旧是一个普通的类,不影响在其它地方的使用。

    然后以上代码还不够完美,假如要给另外一个类实现单例模式,得去修改代理类propxSingleton的代码,不符合设计模式中的开放-封闭原则,得封装一个获取不同类的代理类propxSingletongetPropxSingleton方法。

    const Singleton = function (name) {
      this.name = name;
      this.init();
    }
    Singleton.prototype.init = function () {
      //...初始化
    };
    const getPropxSingleton = function (customClass) {
      return (function () {
        var instance;
        return function (name) {
          if (!instance) {
            instance = new customClass(name);
          }
          return instance;
        }
      })()
    };
    const PropxSingleton = getPropxSingleton(Singleton);
    var a = new PropxSingleton('a');
    var b = new PropxSingleton('b');
    console.log(a === b); //true
    

    用ES6来实现一个单例模式

    以上都是用ES5实现的单例模式,现在都是使用ES6了,故用ES6来实现一个单例模式。

    class Singleton {
      constructor(name) {
        this.name = name;
        this.init();
      }
      init() {
        //...初始化
      }
    }
    const getPropxSingleton = function (customClass) {
      let instance = null;
      return class {
        constructor() {
          if (instance) return instance;
          return instance = new customClass(...arguments)
        }
      }
    };
    const PropxSingleton = getPropxSingleton(Singleton);
    var a = new PropxSingleton('a');
    var b = new PropxSingleton('b');
    console.log(a === b); //true
    

    起源地下载网 » 『面试的底气』—— 设计模式之单例模式|8月更文挑战

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元