阅读 216

听故事学模式 js设计模式-单例模式

前言

  最近在看javascript设计模式与开发实践,虽然之前就看过一部分,但是缺乏记录到最后也忘得7788了,这次要好好看好好记好好学

单例模式是啥

先来看看定义。

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

现实中的单例子模式

  有一天,小明去发廊办了张不记名的会员卡,充了500块钱,代码大概如下

function Card(money) {
    this.money = money;
}
Card.prototype.getMoney = function(){
    console.log(this.money);
}
const card = new Card(500);
card.getMoney(); //500
复制代码

  但是一段时间过后,小明忘记了卡在哪里了,只能又去办了一张卡,又浪费了500块。

function Card(money) {
    this.money = money;
}
Card.prototype.getMoney = function(){
    console.log(this.money);
}
const card = new Card(500);
card.getMoney(); //500
const card2 = new Card(500);
card2.getMoney(); //500
console.log(card === card2); //false
复制代码

  会员卡,小明只需要一张就够了,办了两张,浪费资源,并且发廊也做的不好,应该根据手机号或者身份证等记录下卡的信息。

  后来老板找技术人员小强引进了新的系统,可以判断你是否办过卡,如果办过了就直接可以使用已经办了的卡,这时候就用到了单例模式。再也不怕我的会员卡丢了。

const Card = (function () {
    let instance;
    return function Card(money) {
        if (instance) return instance;、//老哥你已经办过卡了
        this.money = money;
        instance = this;
    }
})()
Card.prototype.getMoney = function () {
    console.log(this.money);
}
const card = new Card(500);
card.getMoney(); //500
const card2 = new Card(500); //老哥不用了,你上次办的卡还有500块呢
card2.getMoney(); //500
console.log(card === card2); //true
复制代码

  这个系统还有点小bug,帮客人办卡之前,一定要点一下new,否则会出错,店员老是忘记,导致很多客人数据丢失了

const Card = (function () {
    let instance;
    return function Card(money) {
        if (instance) return instance;
        this.money = money;
        instance = this;
    }
})()
Card.prototype.getMoney = function () {
    console.log(this.money);
}
const card = Card(500);
card.getMoney(); //Uncaught TypeError: Cannot read property 'getMoney' of undefined
//老子的钱呢??
复制代码

  后面又找了技术人员小强帮忙搞了一下。

const Card = (function () {
    let instance;
    return function Card(money) {
        if (!(this instanceof Card)) throw("new啊!再不记得扣工资了"); //这里当然也可以返回new Card(money)
        if (instance) return instance;
        this.money = money;
        instance = this;
    }
})()
Card.prototype.getMoney = function () {
    console.log(this.money);
}
const card = Card(500);
card.getMoney(); 
复制代码

这下店员如果不记得点下new,帮客人办会员卡的时候,就会弹出错误了。这下稳了

通用单例

  技术人员小强因为接了发廊项目,赚了点小钱,而且越来越多商家找小强搞系统,小强都不想在公司996搬砖了。但是商家太多啊,根本忙不过来,请人又要分一杯羹。有啥办法呢?于是小强又改进了一下系统

const superCard = function(fn){
    if(Object.prototype.toString.call(fn) !== "[object Function]")throw "请正确传入函数";
    let instance;
    return function superCard(...params){
        if(!(this instanceof superCard))throw "请点new";
        return instance?instance:instance = new fn(...params);
    }
}
复制代码

把判断是否办过卡的逻辑抽出来封装好,可以使用于各种商铺,不管你是理发店还是便利店还是洗脚店。

const superCard = function(fn){
    if(Object.prototype.toString.call(fn) !== "[object Function]")throw "请正确传入函数";
    let instance;
    return function superCard(...params){
        if(!(this instanceof superCard))throw "请点new";
        return instance?instance:instance = new fn(...params);
    }
}

const Barber = function(money){
    this.money = money;
}
Barber.prototype.getMoney = function(){
    console.log(this.money);
}
const SuperBarber = superCard(Barber);
const card = new SuperBarber(500);
const card2 = new SuperBarber(500);
card.getMoney(); //500
card2.getMoney(); //500
console.log(card === card2); //true
复制代码

现在小强已经实现了财富自由,赢取白富美,走上人生巅峰。。。。。。

前端中的应用

  回到前端,因为js是一门无类语言,所有的类都是想方设法仿出来的,在js中创建对象非常简单,所以实现最简单的单利模式就是创建一个全局变量,唯一的,全局都能访问的对象。但是全局变量还是要减少使用,我们可以通过命名空间和私有变量等方式去减少对全局变量的使用。

命名空间

var MyApp = {};
MyApp.namespace = function (name) {
    var parts = name.split('.');
    var current = MyApp;
    for (var i in parts) {
        if (!current[parts[i]]) {
            current[parts[i]] = {};
        }
        current = current[parts[i]];
    }
};
MyApp.namespace('event');
MyApp.namespace('dom.style');
复制代码

私有变量

var user = (function () {
    var __name = 'sven',
        __age = 29;
    return {
        getUserInfo: function () {
            return __name + '-' + __age;
        }
    }
})();
复制代码

vuex中的单例模式

保证一个vue实例只会被install一次Vuex插件,这就是单例模式的运用了

  我们常用的react中的状态管理redux中的store也是唯一的,且所有组件都有办法去和它进行数据的交互。又例如前端页面常用的对话框,状态栏,基本也都是一个单例模式,全局只需要一个。这些都是单例模式的体现