单例模式
一,单列模式的介绍1.概念2.示例场景3.UML 类图如下二,单例模式的应用1.模式特性的说明1-1. java实例1-2. `javaScript`的简单实例 - 存在不透明性1-3. 使用代码实现单例模式 - 完成一个透明的单例1-4. 通用的惰性单例三,单列模式的场景项目中的场景单例模式 vs 单一职责原则一,单列模式的介绍
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 instancereturn 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
;(这里当我们写自己的模块时,进行封装使用引入到项目中,也可多一次创建就可使用;避免多次创建带来不必要的损耗)设计原则验证:
符合单一职责原则,只实例化唯一的对象没法具体开放封闭原则,但是绝对不违反开放封闭原则