博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
js单例模式
阅读量:6943 次
发布时间:2019-06-27

本文共 5984 字,大约阅读时间需要 19 分钟。

单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。

通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

为了帮助大家更好地理解单例模式,大家可以结合下面的类图来进行理解,以及后面也会剖析单例模式的实现思路:

下面就看看具体的实现代码(看完之后你会惊讶道:真是这样的!):

///     /// 单例模式的实现    ///     public class Singleton    {        // 定义一个静态变量来保存类的实例        private static Singleton uniqueInstance;        // 定义私有构造函数,使外界不能创建该类实例        private Singleton()        {        }        ///         /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点        ///         /// 
public static Singleton GetInstance() { // 如果类的实例不存在则创建,否则直接返回 if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; } }

上面的单例模式的实现在单线程下确实是完美的,然而在多线程的情况下会得到多个Singleton实例,因为在两个线程同时运行GetInstance方 法时,此时两个线程判断(uniqueInstance ==null)这个条件时都返回真,此时两个线程就都会创建Singleton的实例,这样就违背了我们单例模式初衷了,既然上面的实现会运行多个线程执 行,那我们对于多线程的解决方案自然就是使GetInstance方法在同一时间只运行一个线程运行就好了,也就是我们线程同步的问题了(对于线程同步大家也可以参考我的文章),具体的解决多线程的代码如下:

///     /// 单例模式的实现    ///     public class Singleton    {        // 定义一个静态变量来保存类的实例        private static Singleton uniqueInstance;        // 定义一个标识确保线程同步        private static readonly object locker = new object();        // 定义私有构造函数,使外界不能创建该类实例        private Singleton()        {        }        ///         /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点        ///         /// 
public static Singleton GetInstance() { // 当第一个线程运行到这里时,此时会对locker对象 "加锁", // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁 // lock语句运行完之后(即线程运行完之后)会对该对象"解锁" lock (locker) { // 如果类的实例不存在则创建,否则直接返回 if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } return uniqueInstance; } }

上面这种解决方案确实可以解决多线程的问题,但是上面代码对于每个线程都会对线程辅助对象locker加锁之后再判断实例是否存在,对于 这个操作完全没有必要的,因为当第一个线程创建了该类的实例之后,后面的线程此时只需要直接判断(uniqueInstance==null)为假,此时 完全没必要对线程辅助对象加锁之后再去判断,所以上面的实现方式增加了额外的开销,损失了性能,为了改进上面实现方式的缺陷,我们只需要在lock语句前 面加一句(uniqueInstance==null)的判断就可以避免锁所增加的额外开销,这种实现方式我们就叫它 “双重锁定”,下面具体看看实现代码的:

///     /// 单例模式的实现    ///     public class Singleton    {        // 定义一个静态变量来保存类的实例        private static Singleton uniqueInstance;        // 定义一个标识确保线程同步        private static readonly object locker = new object();        // 定义私有构造函数,使外界不能创建该类实例        private Singleton()        {        }        ///         /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点        ///         /// 
public static Singleton GetInstance() { // 当第一个线程运行到这里时,此时会对locker对象 "加锁", // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁 // lock语句运行完之后(即线程运行完之后)会对该对象"解锁" // 双重锁定只需要一句判断就可以了 if (uniqueInstance == null) { lock (locker) { // 如果类的实例不存在则创建,否则直接返回 if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; } }

理解完了单例模式之后,菜鸟又接着问了:.NET FrameWork类库中有没有单例模式的实现呢?

经过查看,.NET类库中确实存在单例模式的实现类,不过该类不是公开的,下面就具体看看该类的一个实现的(该类具体存在于System.dll程序集,命名空间为System,大家可以用反射工具Reflector去查看源码的):

// 该类不是一个公开类    // 但是该类的实现应用了单例模式    internal sealed class SR    {        private static SR loader;        internal SR()        {        }        // 主要是因为该类不是公有,所以这个全部访问点也定义为私有的了        // 但是思想还是用到了单例模式的思想的        private static SR GetLoader()        {            if (loader == null)            {                SR sr = new SR();                Interlocked.CompareExchange
(ref loader, sr, null); } return loader; } // 这个公有方法中调用了GetLoader方法的 public static object GetObject(string name) { SR loader = GetLoader(); if (loader == null) { return null; } return loader.resources.GetObject(name, Culture); } }

 

js单例模式:

var createLoginLayer = (function(){    var div;    return function(){        if(!div){            div = document.createElement('div');            div.innerHTML = '我是登录浮窗';             div.style.display = 'none';            document.body.appendChild(div);        }        return div;    }})(); 调用:document.getElementById('loginBtn').onclick = function(){                var loginLayer = createLoginLayer();                loginLayer.style.display = 'block';            };

 

用代理实现单例模式:

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('sven1');var b = new ProxySingletonCreateDiv('sven2');

 

js通用的惰性单列 :

var getSingle = function(fn){    var result;    return function(){        return result || ( result = fn.apply(this,arguments));    }};var createLoginLayer = function(){    var div = document.createElement('div');    div.innerHTML = '我是登录浮窗';     div.style.display = 'none';    document.body.appendChild(div);    return div;};var createSingleLoginLayer = getSingle(createLoginLayer);document.getElementById('loginBtn').onclcik = function(){    var loginLayer = createSingleLoginLayer();    loginLayer.style.display = 'block';}; var createSingleIframe = getSingle(function(){    var iframe = document.createElement('iframe');    document.body.appendChild(iframe);    return iframe; });document.getElementById('loginBtn').onclick = function(){    var loginLayer = createSingleIframe();    loginLayer.src = 'http://baidu.com';};

 

转载于:https://www.cnblogs.com/gongshunkai/p/6627358.html

你可能感兴趣的文章
图案研究2--九格定义
查看>>
【高并发解决方案】4、秒杀系统架构分析与实战
查看>>
原型与原型链详解
查看>>
高性能IOT服务器实现之路
查看>>
iOS混合开发库(GICXMLLayout)布局案例分析(2)闲鱼案例
查看>>
C、C++、Java、JavaScript、PHP、Python分别用来开发什么?
查看>>
测试格式
查看>>
超级课程表API
查看>>
puppet客户端取消主动更新
查看>>
redis 3.0.7 安装部署
查看>>
<Power Shell>新的征程
查看>>
SQLite操作
查看>>
奔向新纪元,Vista安装经历
查看>>
应用强制访问控制管理网络服务
查看>>
Mellanox发布升级版RoCE软件 简化以太网RDMA部署
查看>>
大数据产业“跑”出“长春速度”
查看>>
我的友情链接
查看>>
mysql把一个表某个字段的内容复制到另一张表的某个字段的SQL语句写法
查看>>
我的友情链接
查看>>
安卓constraintLayout中app:srcCompat设置的图片显示不出来
查看>>