职业IT人-IT人生活圈

 找回密码
 成为会员
搜索
查看: 396|回复: 9

单例/单体模式(Singleton)

[复制链接]
曾经的小孩 发表于 2011-8-29 09:28 | 显示全部楼层 |阅读模式
首先,单例模式是作为对象的创建模式,此外还包括工厂模式。单例模式的三个特点:
1,该类只有一个实例
2,该类自行创建该实例(在该类内部创建自身的实例对象)
3,向整个系统公开这个实例接口

java中大概是这个样子:

  
class Singleton {   
      
    //私有,静态的类自身实例   
    private static Singleton instance = new Singleton();   
      
    //私有的构造子(构造器,构造函数,构造方法)   
    private Singleton(){}   
      
    //公开,静态的工厂方法   
    public static Singleton getInstance() {   
        return instance;   
    }   
}  

class Singleton {
       
        //私有,静态的类自身实例
        private static Singleton instance = new Singleton();
       
        //私有的构造子(构造器,构造函数,构造方法)
        private Singleton(){}
       
        //公开,静态的工厂方法
        public static Singleton getInstance() {
                return instance;
        }
}
使用时:
Singleton obj = Singleton.getInstance();

这个单例类在自身被加载时instance会被实例化,即便加载器是静态的。
因此,对于资源密集,配置开销较大的单体更合理的做法是将实例化(new)推迟到使用它的时候。
即惰性加载(Lazy loading),它常用于那些必须加载大量数据的单体。修改下:

  
class LazySingleton {   
    //初始为null,暂不实例化   
    private static LazySingleton instance = null;   
      
    //私有的构造子(构造器,构造函数,构造方法)   
    private LazySingleton(){}   
      
    //公开,静态的工厂方法,需要使用时才去创建该单体   
    public static LazySingleton getInstance() {   
        if( instance == null ) {   
            instance = new LazySingleton();   
        }   
        return instance;   
    }      
}  

class LazySingleton {
        //初始为null,暂不实例化
        private static LazySingleton instance = null;
       
        //私有的构造子(构造器,构造函数,构造方法)
        private LazySingleton(){}
       
        //公开,静态的工厂方法,需要使用时才去创建该单体
        public static LazySingleton getInstance() {
                if( instance == null ) {
                        instance = new LazySingleton();
                }
                return instance;
        }       
}  
使用方式同上。

单例模式是javascript最基本,最有用的模式之一。它提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码通过单一的变量进行访问。
单体在javascipt中有许多用处,可以用来划分命名空间,以减少全局变量的泛滥。还可以用在分支技术中用来处理各浏览器的差异。
javascript中单例模式的实现方式有多种,每一种都有自身的优点或缺点:

1,对象直接量实现最基本,最简单的单体

Js代码  
var Singleton = {   
    attr1 : 1,   
    attr2 : 'hello',   
    method1 : function(){alert(this.attr2);},   
    method2 : function(arg){}   
}  

var Singleton = {
        attr1 : 1,
        attr2 : 'hello',
        method1 : function(){alert(this.attr2);},
        method2 : function(arg){}
}
这种方式中,对象所有成员都通过Singleton加点号访问。所有成员是公开的,没有私有的。
在执行到变量Singleton时,会加载(实例化)自身,即非惰性加载。
此外method1用this访问单体的其它成员会存在一些风险,因为method1的上下文不是总是指向Singleton对象。
比如当把method1作为事件监听器时,this可能指向的是dom元素,这时可能会提示undefined。


2,闭包实现私有成员的单体

Js代码  
var Singleton = function(){   
    var attr = 1, fn = function(){};   
    return {   
        method : function(){ fn(); },   
        getAttr : function(){ return attr; }           
    };     
}();  

var Singleton = function(){
        var attr = 1, fn = function(){};
        return {
                method : function(){ fn(); },
                getAttr : function(){ return attr; }               
        };       
}();
这种方式中var定义私有的成员属性attr,方法fn,然后返回一个公开的接口method和getAttr。
今后修改实现时,接口方法method和getAttr不变,只需修改私有的attr和fn的具体实现。
使用如下:

Singleton.method();
Singleton.getAttr();

3,闭包实现私有成员的惰性实例化单体

Js代码  
var LazySingleton = function(){   
    var attr = 1, fn = function(){};   
    var obj = {   
        method : function(){ fn(); },   
        getAttr : function(){ return attr; }   
    };   
    function init(){   
        return obj;   
    }   
    return {getInstace: init};   
}();  

var LazySingleton = function(){
        var attr = 1, fn = function(){};
        var obj = {
                method : function(){ fn(); },
                getAttr : function(){ return attr; }
        };
        function init(){
                return obj;
        }
        return {getInstace: init};
}();
  
适用场合上面已经提到:对于那些必须加载大量数据的单体直到需要使用它的时候才实例化。使用方式是这样的:

LazySingleton.getInstance().method();
LazySingleton.getInstance().getAttr();



附件:js单例模式实现事件管理模块的各个版本练习。


Event.rar (20.9 KB)
下载次数: 109

钰云 发表于 2011-8-29 09:28 | 显示全部楼层
应该考虑到多线程环境下,还有序列化情况下。

broken 发表于 2011-8-29 09:28 | 显示全部楼层
楼上的看过effective java吧

走就走吧 发表于 2011-8-29 09:29 | 显示全部楼层
class LazySingleton {
//初始为null,暂不实例化
private static Singleton instance = null;

//私有的构造子(构造器,构造函数,构造方法)
private Singleton(){}

//公开,静态的工厂方法,需要使用时才去创建该单体
public static Singleton getInstance() {
if( instance == null ) {
instance = new LazySingleton();
}
return instance;
}
}
唉,看不懂

走就走吧 发表于 2011-8-29 09:29 | 显示全部楼层
  
class LazySingleton {   
    //初始为null,暂不实例化   
    private static Singleton instance = null;   
      
    //私有的构造子(构造器,构造函数,构造方法)   
    private Singleton(){}   
      
    //公开,静态的工厂方法,需要使用时才去创建该单体   
    public static Singleton getInstance() {   
        if( instance == null ) {   
            instance = new LazySingleton();   
        }   
        return instance;   
    }      
}  

class LazySingleton {
        //初始为null,暂不实例化
        private static Singleton instance = null;
       
        //私有的构造子(构造器,构造函数,构造方法)
        private Singleton(){}
       
        //公开,静态的工厂方法,需要使用时才去创建该单体
        public static Singleton getInstance() {
                if( instance == null ) {
                        instance = new LazySingleton();
                }
                return instance;
        }       
}


理论上这里可能getInstance()获得的对象是非线程安全的

醉倚西风 发表于 2011-8-29 09:29 | 显示全部楼层
多线程情况下使用双锁机制,就解决了。

fossil 发表于 2011-8-29 09:29 | 显示全部楼层
解决多线程的问题有3种方案:
1,直接用同步getInstance()方法,该方法不考虑性能的开销
2,早实例(early instantiate),即相对于懒实例。
3.双锁机制。前提:至少jdk1.5

郁闷小男人 发表于 2011-8-29 09:29 | 显示全部楼层
真的不错,现在做项目自己编写的这方面的代码很少,好好学习学习

愚人 发表于 2011-8-29 09:29 | 显示全部楼层
Lazy loading singleton 一般实现采用:
  
public static Singleton getInstance() {   
  if (instance == null) {   
    synchronized(Singleton.class) {   
      if (instance == null) instance = new Singleton();   
    }   
  }   
  return instance;   
}  

public static Singleton getInstance() {
  if (instance == null) {
    synchronized(Singleton.class) {
      if (instance == null) instance = new Singleton();
    }
  }
  return instance;
}


还有一种最高效的实现,由java设计者写出来的
  
public class Singleton {   
  
  private static final class A {   
    public static final Singleton s = new Singleton();   
  }   
     
  private Singleton() {   
      
  }   
     
  public static Singleton getInstance() {   
    return A.s;   
  }   
}  

public class Singleton {

  private static final class A {
    public static final Singleton s = new Singleton();
  }
  
  private Singleton() {
   
  }
  
  public static Singleton getInstance() {
    return A.s;
  }
}


ksdal 发表于 2011-8-29 09:29 | 显示全部楼层
我记得这样的方式,如果使用反射,访问控制会无效
您需要登录后才可以回帖 登录 | 成为会员

本版积分规则

QQ|手机版|小黑屋|网站帮助|职业IT人-IT人生活圈 ( 粤ICP备12053935号-1 )|网站地图
本站文章版权归原发布者及原出处所有。内容为作者个人观点,并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是信息平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽造成漏登,请及时联系我们,我们将根据著作权人的要求立即更正或者删除有关内容。

GMT+8, 2024-4-27 19:08 , Processed in 0.111202 second(s), 20 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表