JavaScript设计模式二(单例模式)

JavaScript设计模式二(单例模式)

这边文章主要是JavaScript中的单例模式
定义:

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

其实我们的日常开发中或多或少的用到了单例模式的方法。例如我们做Electron开发的过程中,点击一个按钮创建了一个窗口,后续点击的时候,如果窗口已经存在了就focus窗口,否则创建;或者我们经常会创建一个定时任务,同时把定时任务赋值给一个变量,如果变量不存在就创建,否则不创建。但是大多数情况我们都是利用的是一个变量来控制的。接下来我们看看代码的实现

实现单例模式

其实上面的介绍我们已经说了实现单例模式的思路,就是通过一个变量来控制

var Singleton=function(name) {
    this.name=name;
    this.instance=null;
}
Singleton.prototype.getName=function(){
    console.log(this.name);
}
Singleton.getInstance=function(name) {
    if(!this.instance) {
        this.instance = new Singleton(name);
    }
    return this.instance;
}

//这种写法借助了this.instance,其实可以不需要

var Singleton = function(name) {
    this.name=name;
}
Singleton.prototype.getName=function(){
    console.log(this.name);
}
Singleton.getInstance=(function(){
    var instance = null;
    return function(name) {
        if(!instance) {
            instance = new Singleton(name);
        }
        return instance;
    };
})();

使用方法:

var a = Singleton.getInstance('a');
var b = Singleton.getInstance('b');
a===b

这种方式实现了我们说的单例模式,但是有一个很明显的缺点,就是我们实例化的时候不是使用的new方法来实例化,而是用的getInstance方法,也就是说我们必须知道这个类是单例类,才能这样去用,这就增加了不透明性。

透明的单例模式

所谓的透明的单例模式,就是我们可以像正常的类那样去new一个单例类。

var CreateDiv = (function(){
    var instance;
    var CreateDiv = function(html) {
        if (instance) {
            return instance;
        }
        this.html = html;
        this.init();
        return instance = this;
    };
    
    CreateDiv.prototype.init = function() {
        var div = document.createElement('div');
        div.innerHTML = this.html;
        document.body.appendChild('div');
    };
    
    return CreateDiv;
})();

var a = new CreateDiv('div');
var b = new CreateDiv('div');

a===b

之所以能够通过new来创建一个单例类的实例,是因为CreateDiv
的返回值是一个构造函数,这个构造函数做了两件事情

  • 创建对象和执行init方法
  • 保证只有一个对象

我们可以想象如果需求变成了,我们需要CreateInput之类,是不是一直要修改这个类呢?

代理实现单例模式

利用代理就可以很好的解决上面的问题

var CreateDiv = function(html) {
    this.html = html;
    this.init();
}

CreateDiv.prototype.init = function() {
   var div = document.createElement('div');
   div.innerHTML = this.html;
   document.body.appendChild('div');
};

var ProxySingletonCreateDiv = (function(){
    var instance;
    return function(html) {
        if (!instance) {
            instance = new CreateDiv(html);
        }
        return instance;
    }
})();


var a = new ProxySingletonCreateDiv('div');
var b = new ProxySingletonCreateDiv('div');

利用代理类,我们遵循了单一职责的原则,让代理类负责单例的逻辑,CreateDiv变成一个普通的创建html的类,两者结合达到单例模式的效果

JavaScript中的单例模式

JavaScript单例模式的核心是:

确保只有一个实例,并提供全局访问

与传统的面向对象语言不一样,JavaScript可以定义全局变量,而且我们通常认为全局变量就是一个单例,但是这种使用方式很容易造成命名空间的污染,针对这种问题有两种办法

  • 使用命名空间
    最简单的就是使用字面量常量:
var namespace1 = {
    a: function(){},
    b: 'bbbb'
}
  • 利用闭包封装变量

var user = (function(){
    
    var _user = 'hahaha';
    return {
        setUserName: function(name) {
            _user = name;
        },
        getUserName: function(){
            console.log(_user);
        }
    }
})();

惰性单例

定义:

惰性单例是指需要时才创建的单例

上面的那几种方法实际上就是惰性单例,但是那些事面向对象的,我们看看JavaScript中的惰性单例,看一段PC版的代码吧

let historyWindow = null;
ipc.on(cfg.CHANNEL.LOCAL.CHAT.SEARCH_HISTORY, function(event, arg) {
  if (!historyWindow) {
    historyWindow = new BrowserWindow({
      width: 621,
      height: 540,
      minWidth: 621,
      minHeight: 540,
      frame: false,
      show: false,
    });
    historyWindow.setAutoHideMenuBar(false);
    historyWindow.loadURL('file://' + __dirname + '/../../../client/views/history.html');
    if (process.env.NODE_ENV == 'dev') {
      historyWindow.webContents.openDevTools();
    }
    historyWindow.on('close', function() {
      historyWindow.webContents.closeDevTools();
    });
    historyWindow.on('closed', function() {
      glb.set(cfg.GLB.HISTORY_WINDOW, null);
      glb.remove(cfg.GLB.ADD_MEMBER_WINDOW);
      historyWindow = null;
    });
    historyWindow.webContents.on('did-finish-load', function() {
      glb.set(cfg.GLB.HISTORY_WINDOW, historyWindow);
      historyWindow.show();
      historyWindow.focus();
      historyWindow.webContents.send(cfg.CHANNEL.LOCAL.CHAT.OPEN_HISTORY_WINDOW_RECV, arg);
    });
  } else {
    historyWindow.webContents.send(cfg.CHANNEL.LOCAL.CHAT.OPEN_HISTORY_WINDOW_RECV, arg);
    if (historyWindow.isMinimized()) {
      historyWindow.show();
    } else {
      historyWindow.focus();
    }
  }
});

这段代码的逻辑是,点击历史消息的icon,创建一个历史消息的弹出框,后面如果继续点击,就把之前的弹出框focus。

这里其实还有优化的空间,我们知道electron创建一个新的BrowserWindow是很慢的,所以我们创建一次之后,用户点击关闭,其实可以隐藏起来,并不是实际的关闭,这样当用户点击第二次的时候就省略了创建窗口的过程,直接渲染数据就可以。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 单例模式(SingletonPattern)一般被认为是最简单、最易理解的设计模式,也因为它的简洁易懂,是项目中最...
    成热了阅读 4,196评论 4 34
  • 1 单例模式的动机 对于一个软件系统的某些类而言,我们无须创建多个实例。举个大家都熟知的例子——Windows任务...
    justCode_阅读 1,428评论 2 9
  • 第3章 基本概念 3.1 语法 3.2 关键字和保留字 3.3 变量 3.4 数据类型 5种简单数据类型:Unde...
    RickCole阅读 5,074评论 0 21
  • 总结一下今年感觉还不错 中的
    7a433e1f1491阅读 151评论 0 0