js设计模式的讲解与应用 - 【单例模式】

一,单列模式的介绍

1.概念

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例;
单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

2.示例场景

按照面向对象的编程思想,任何东西都可以抽象为一个类,然后可以new出若干个对象。
但是针对某些场景,只能存在唯一的对象;
例如:jQuery中的$; 登录;购物车等;

3.UML 类图如下

在这里插入图片描述

二,单例模式的应用

1.模式特性的说明

  • 单例模式需要使用到java的特性(private
  • ES6中并没有使用private的关键字;(暂时还没有规范到ES6中,但typeScript除外)
1-1. java实例

单例模式用到了 java 的一些特性,而 es6 没有这些特性,所有这里使用 java 进行演示,代码如下:

public class SingleObject {
    // 注意,私有化构造函数,外部不能 new ,只能内部能 new !!!!
    private SingleObject(){
    }
    // 唯一被 new 出来的对象
    private SingleObject instance = null;
    // 获取对象的唯一接口
    public SingleObject getInstance() {
        if (instance == null) {
            // 只 new 一次
            instance = new SingleObject();
        }
        return instance;
    }

    // 对象方法
    public void login(username, password){
      System.out.println("login...");
   }
}

使用代码

public class SingletonPatternDemo {
   public static void main(String[] args) {
      //不合法的构造函数
      //编译时错误:构造函数 SingleObject() 是不可见的 !!!
      //SingleObject object = new SingleObject();

      //获取唯一可用的对象
      SingleObject object = SingleObject.getInstance();
      object.login();
   }
}

单例模式的关键在于不能让外部使用者 new 出对象,即构造函数是 private

这里的关键字样表示:
public 公有的
protect 受保护
private 私有

1-2. javaScript的简单实例 - 存在不透明性

这里通过SingleObject.getInstance来获取SingleObject唯一的类,相对较简单,但存在一个问题;这个类的不透明性SingleObject使用者必须知道这是个单例类;
跟以往的 new XXX的方式获取不同,这里使用SingleObject.getInstance来获取对象;实例代码如下:

class SingleObject {
    login() {
        console.log('login...')
    }
}
SingleObject.getInstance = (function () {
    let instance
    return function () {
        if (!instance) {
            instance = new SingleObject();
        }
        return instance
    }
})()

// 测试:注意这里只能使用静态函数 getInstance ,不能 new SingleObject() !!!
let obj1 = SingleObject.getInstance()
obj1.login()
let obj2 = SingleObject.getInstance()
obj2.login()
console.log(obj1 === obj2)  // 两者必须完全相等
1-3. 使用代码实现单例模式 - 完成一个透明的单例

这里使用到“单一职责的原则”,将创建对象对象的初始化方法进行分离;
这里把负责管理单例的逻辑移到了代理类ProxySingletonObject中,而实现单例的SingleObject变成一个普通的类,结合起来实现单例的效果;代码实例如下:

// 实例的构造函数
class SingleObject {
   login() {
       console.log('login...');
   }
}
// ProxySingletonObject 引入一个代理类
var ProxySingletonObject = (function(){ 
   var instance;
   return function(){
       if (!instance){
           instance = new SingleObject();
       }
       return instance;
   }
})();
var login1 = new ProxySingletonObject()
var login2 = new ProxySingletonObject()
console.log(login1 === login2, "login1 === login2");
1-4. 通用的惰性单例

单列的逻辑:用一个变量来标志是否创建过对象,如已创建,下次直接返回已创建好的对象;

var obj;
if (!obj) {
	obj = XXX;
}

这里将创建实例对象的职责管理单列的职责分开;createLoginLayer的方法可用于创建多种,随时替换方法;

// 创建对象的实例:
var createLoginLayer = function(){
	var div = document.createElement( 'div' );
	div.innerHTML = '我是登录浮窗';
	div.style.display = 'none';
	document.body.appendChild( div );
	return div;
};
// 单列的逻辑
var getSingle = function(fn) {
    console.log(fn)
    var result;
    return function() {
        return result || (result = fn.apply(this, arguments))
    }
}
// 调用单列的逻辑创建createLoginLayer的单列
var createSingleLoginLayer = getSingle( createLoginLayer ); 

document.getElementById( 'loginBtn' ).onclick = function(){
    var loginLayer = createSingleLoginLayer(); // 登录框的createLoginLayer只有一个
    loginLayer.style.display = 'block';
}; 

三,单列模式的场景

常使用中,很多都用到了单例的思想,但是不一定完全按照单例的类图来实现:

项目中的场景

  • jQuery 只有一个 $
    在项目中应用jQuery的文件,有且只有一个$,其内部调整逻辑也类似:
// jQuery 只有一个 `$`
if (window.jQuery != null) {
    return window.jQuery
} else {
    // 初始化...
}
  • 模拟实现一个登录框
  • 购物车
  • redux 和 vuex 的 store

单例模式 vs 单一职责原则

  • 单一职责原则是针对所有的设计,单个功能尽量拆分,一个模块做好一个功能。如果做不好,会带来模块臃肿,不好维护。
  • 单例模式是系统的有且只有一份数据,如果不这样做,会出 bug ;(这里当我们写自己的模块时,进行封装使用引入到项目中,也可多一次创建就可使用;避免多次创建带来不必要的损耗)

设计原则验证:

  • 符合单一职责原则,只实例化唯一的对象
  • 没法具体开放封闭原则,但是绝对不违反开放封闭原则
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值