细品 javascript 设计模式(单例模式)
发布于 4 年前 作者 shixinglong007 3540 次浏览 来自 分享

我尽量用最少的文字,最少的篇幅,讲明白设计模式的方方面面。 文章连接

理解单例模式

确保只有一个实例,并提供全局访问。
例如 redux 中的 store,线程池,全局缓存,浏览器 window 对象等。

上代码:通用的惰性单例模式

let getSingle = function(fn) {
    let result = 'initial_single';
    return function() {
        if (result === 'initial_single') {
            result = fn.apply(this, arguments);
        }
        return result;
    }
}

// 测试 -----
let Tree = function() {
    console.log('something')
}
let getSingleTree = getSingle(Tree)
getSingleTree() // 第一次调用时输出:console.log('something')
getSingleTree() //
getSingleTree() //

// 调用三次只会输出一次

单例模式的演进过程

1. 普通单例

用变量来标记某个对象是否被创建过,如果是直接返回之前创建的变量

上代码:

let Person = function(name) {
    this.name = name
}
Person.prototype.getName = function() {
    console.log(this.name)
}
Person.getSingle = (function() {
    let instance = null;
    return function(name) {
        if (!instance) {
            instance = new Person(name)
        }
        return instance
    }
})();

2. 透明单例

有一个类,不论你 new 多少次。它都给你返回第一次 new 的那个实例。这就是透明的单例模式,所谓透明,就是你不能看出它是单例。

上代码:

let Person = (function() {
    let instance;
    Person = function(name) {
        if (instance) {
            return instance;
        }
        this.name = name;
        return instance = this;
    }
    return Person;
})();
let p = new Person('C#')
let a = new Person('java')
console.log(p === a) // true

3. 用代理实现单例

之前的单例实现都有一个共同的问题:类和单例的代码都交织在一起。这样有违反“单一职能”原则。

代理,就是把类应该做的事,和单例应该做的事情分开 上代码:

// 类
var Person = function(name) {
    this.name = name;
}
// 代理
let ProxySinglePerson = (function() {
    let result;
    return function(name) {
        if (result) {
            return result
        }
        result = new Person(name)
        return result
    }
})();

let p = new ProxySinglePerson('C#')
let a = new ProxySinglePerson('java')
console.log(p === a) // true

5. 惰性单例

意思是,需要用到的时候才创建。这是单例模式的应用中非常重要的一点。
其实之前的代码中也已经包含了惰性单例,看下面代码。重点关注“惰性”。

上代码:

// 类
var Person = function(name) {
    this.name = name;
}
Person.getSingle = (function() {
    let instance;
    return function(name) {
        if (!instance) {
            instance = new Person(name);
        }
        return instance;
    }
})();
var p = Person.getSingle('C#')
var a = Person.getSingle('java')
console.log(p === a) // true

6. 通用的惰性单例

一劳永逸,这次咱们完成一个通用的惰性单例。也就是文章开头的那段代码
let getSingle = function(fn) {
    let result = 'initial_single';
    return function() {
        if (result === 'initial_single') {
            result = fn.apply(this, arguments);
        }
        return result;
    }
}

小结

本章学习了单例模式的演进过程,还提到了代理模式和单一职责原则。之后的文章里我会对他们做详细的讲解。

在 getSingle 函数中,也提到了闭包和高阶函数的概念。单例模式是一种非常实用的模式,特别是惰性单例技术,在合适的时候才创建对象,并且全局唯一。更奇妙的是创建对象和管理单例的职责被分布在两个不同的方法中,这两个方法组合起来才有单例模式的威力。 web_access_2.png

2 回复

单例?单利?

@kidbai 妈耶~ 整错了

回到顶部