2008-01-25

设计模式-单例模式

关键字: 设计模式
1.概念
《设计模式》一书中对于Singleton模式是这样定义的:保证一个类有且仅有一个实例,并且提供了一个全局的访问点。

2.动机
在很多操作中,比如建立目录,打印机,数据库连接都需要这样的单线程操作,如果一个类有多个实例存在的话,就可能带来并发的问题。
这就提出了一个问题:一般每个类中的构造函数都是public,如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?这就是单例模式需要解决的问题。
为了防止单态模式的类被多次实例化,应将类的构造器设成private或protected,这样就保证了只能通过静态方法获得类实例。如果构造器设置为private,那么就不能单例的子类。而该静态方法则保证每次返回的实例都是同一个,这就需将该类的实例设置成类属性,由于该属性需要被静态方法访问,因此该属性应设成静态属性。

3.适用性
在什么情况下需要使用单例模式呢?
(1)、当类只能有一个实例而且使用者可以从一个众所周知的访问点访问它。
(2)、当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。这点就引出了登记式单例。

4.Java实现
1、饿汉式 在下面这个例子中,这个类被加载时,静态变量m_instance 会被初始化,此时类的私有构造子会被调用。这时候,单例类的惟一实例就被创建出来了。
//饿汉式:     
public class EagerSingleton {  
/** @label Creates */     
private static final EagerSingleton m_instance = new EagerSingleton(); 
/** 
* 私有的默认构造函数 
*/ 
private EagerSingleton() { }    

/** 
* 静态工厂方法 
*/   
public static EagerSingleton getInstance() {     
return m_instance;     
}  
} 

2、懒汉式
//懒汉式 
//使用到才实例化 不使用不实例化,比如你使用此类的其他静态方法 而饿汉式只要用到就被实例化
public class LazySingleton     
{     
private LazySingleton() { }    

//对静态工厂方法使用了同步化,以处理多线程环境
synchronized public static LazySingleton getInstance()     
{     
   if (m_instance == null)     
   {     
       m_instance = new LazySingleton();     
   }     
   return m_instance;     
  }    
} 

注:(1)、从资源利用效率角度来讲,饿汉式比懒汉式单例类稍差些。
  (2)、从速度和反应时间角度来讲,饿汉式比懒汉式单例类稍好些。
3、登记式
//登记式:       
import java.util.HashMap; 
public class RegSingleton 
{ 
  static private HashMap m_registry = new HashMap(); 
  static 
  { 
    RegSingleton x = new RegSingleton(); 
    m_registry.put( x.getClass().getName() , x); 
  } 
  /** 
  * 保护的默认构造子 
  */ 
  protected RegSingleton() {} 
  /** 
  * 静态工厂方法,返还此类惟一的实例 
  */ 
  static public RegSingleton getInstance(String name) 
  { 
    if (name == null) 
    { 
      name = "com.javapatterns.singleton.demos.RegSingleton"; 
    } 
  if (m_registry.get(name) == null) 
  { 
    try 
    { 
       m_registry.put( name,Class.forName(name).newInstance() ) ; 
    } 
    catch(Exception e) 
    { 
       System.out.println("Error happened."); 
    } 
   } 
   return (RegSingleton) (m_registry.get(name) ); 
  } 
   /** 
   * 一个示意性的商业方法 
   */ 
   public String about() 
   { 
      return "Hello, I am RegSingleton."; 
   }
}       

它的子类RegSingletonChild 需要父类的帮助才能实例化。
import java.util.HashMap; 
public class RegSingletonChild extends RegSingleton 
{ 
  public RegSingletonChild() {} 
  /** 
  * 静态工厂方法 
  */ 
  static public RegSingletonChild getInstance() 
  { 
    return (RegSingletonChild) 
    RegSingleton.getInstance( "com.javapatterns.singleton.demos.RegSingletonChild" ); 
} 
  /** 
  * 一个示意性的商业方法 
  */ 
  public String about() 
  { 
    return "Hello, I am RegSingletonChild.";  
  }
}

缺点:
1、RegSingletonChild类的构造函数是public,就等于允许了以这样方式产生实例而不在父类的登记中。

2、GoF 曾指出,由于父类的实例必须存在才可能有子类的实例,这在有些情况下是一个浪费。

5.注意
1、getInstance() 是静态的;
2、构造函数是protected或private;
3、尽量不要将类声明为静态的;

待续设计模式-单例模式(续)
评论
发表评论

您还没有登录,请登录后发表评论

ldjsyl
搜索本博客
我的相册
C64aa706-46c3-3a75-8cd1-1d72023decc4-thumb
新建 BMP 图像
共 12 张
存档
最新评论