JavaScript 设计模式(一):单例模式

JavaScript 设计模式(一):单例模式

一、基本模式

1、定义:

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

2、核心:

  使用闭包存储全局实例。

3、实现:
// Root类
function Root(name) {
    this.name = name
    this.show = function () {
        console.log(this.name)
    }
}
// 单例函数
function Single() {
    var root
    return function (name) {
        if (!root) {
            root = new Root(name)
        }
        return root
    }
}
// 单例函数实例(每个函数维护各自的全局实例)
// (BaseSingle是一个函数)
const BaseSingle = new Single() 
const BaseSingle2 = new Single() 

// 调用实例
BaseSingle('a').show()  // a
BaseSingle('b').show()  // a
BaseSingle2('b').show()  // b
BaseSingle2('a').show()  // b

二、扩展模式

  上面的例子,可以设置唯一的全局Root实例。可是当我们想要设置Apple实例时,我们就必须去修改这个函数,也就破坏了开放封闭原则

  我们如何去创建不同类型的全局唯一实例呢?

  通过观察,我们可以发现,全局实例是通过 root = new Root(name) 来设置的。

  那么,我们可以通过外界传入值的方式,来实现创建不同类型实例的效果吗?

  当然可以!这里有两种方式来扩展。

1、传对象类
// Root类
function Root(name) {
    this.name = name
    this.show = function () {
        console.log('Root: ', this.name)
    }
}
// Apple类
function Apple(size, kg) {
    this.size = size,
    this.kg = kg
    this.isGood = true
    this.show = function () {
        console.log('Apple: ', this.size, this.kg, this.isGood)
    }
}

// 单例函数
function SingleExt (objClass) {
    var instance
    
    return function (...args) {
        if (!instance) {
            instance = new objClass(...args)
        }
        return instance
    }
}

const extSingle = new SingleExt(Root)
const extSingle2 = new SingleExt(Apple)

extSingle('a').show()   // a
extSingle('b').show()   // a
extSingle2(1, 2).show() // 1 2 true
extSingle2(3, 4).show() // 1 2 true

2、传函数
// Root类
function Root(name) {
    this.name = name
    this.show = function () {
        console.log('Root: ', this.name)
    }
}
// Apple类
function Apple(size, kg) {
    this.size = size,
    this.kg = kg
    this.isGood = true
    this.show = function () {
        console.log('Apple: ', this.size, this.kg, this.isGood)
    }
}

// 单例函数
function SingleExt (fn) {
    var instance
    
    return function () {
        if (!instance) {
            instance = fn.apply(this, arguments)
        }
        return instance
    }
}

const extSingle = new SingleExt((name) => {
    return new Root(name)
})
const extSingle2 = new SingleExt((size, kg) => {
    return new Apple(size, kg)
})

extSingle('a').show()   // a
extSingle('b').show()   // a
extSingle2(1, 2).show() // 1 2 true
extSingle2(3, 4).show() // 1 2 true

3、两种方式的比较

  你可能会有疑问,通过传入对象类的形式已经可以实现创建不同类型的全局实例了,为什么还需要使用传入函数的形式呢?

  答案是:为了易于扩展,实现类似于代理的效果。

  例如:市场上定义了,一个苹果的size小于10,则说明是坏的,它的isGood就会设置为false。

  如果使用传入对象类的形式,我们只会得到一个初始化的实例,需要额外去设置对象的isGood属性。

  如果使用传入函数的形式,我们可以在函数中加各种判定,创建并设置对应的实例,之后返回该实例。

(参考代码如下:)

// Root类
function Root(name) {
    this.name = name
    this.show = function () {
        console.log('Root: ', this.name)
    }
}
// Apple类
function Apple(size, kg) {
    this.size = size,
    this.kg = kg
    this.isGood = true
    this.show = function () {
        console.log('Apple: ', this.size, this.kg, this.isGood)
    }
}

// 单例函数
function SingleExt (fn) {
    var instance
    
    return function () {
        if (!instance) {
            instance = fn.apply(this, arguments)
        }
        return instance
    }
}

const extSingle = new SingleExt((name) => {
    return new Root(name)
})
const extSingle2 = new SingleExt((size, kg) => {
    var apple = new Apple(size, kg)
    if (size < 10) {    // 如果 size < 10, 说明是坏的,则 isGood = false
        apple.isGood = false
    }
    return apple
})

extSingle('a').show()   // a
extSingle('b').show()   // a
extSingle2(1, 2).show() // 1 2 false
extSingle2(3, 4).show() // 1 2 false



参考资料:
  1、JavaScript中常见的十五种设计模式
  2、JavaScript设计原则&&常用设计模式

<<< 上一篇:JavaScript 设计模式(零):设计原则
>>> 下一篇:JavaScript 设计模式(二):策略模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值