日志文章

2007年11月10日 09:52:42

设计模式之单例模式

作为对象的创建模式[GOF95], 单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。这个类称为单例类。
  显然单例模式的要点有三个;一是类只能有一个实例;二是它必须自行创建这个实例(因此单例对象持有对自己的引用);三是它必须自行向整个系统提供这个实例。
  常见的应用有windows的回收站和资源管理器.
//代码引用阎宏博士的《Java与模式》一书
代码清单1:饿汉式单例类

public class EagerSingleton
{
private static final EagerSingleton m_instance =
new EagerSingleton();
/**
* 私有的默认构造子
*/
private EagerSingleton() { }
/**
* 静态工厂方法
*/
public static EagerSingleton getInstance()
{

·224·Java 与模式
return m_instance;
}
}

代码清单2:懒汉式单例类

package com.javapatterns.singleton.demos;
public class LazySingleton
{
private static LazySingleton
m_instance = null;
/**
* 私有的默认构造子,保证外界无法直接实例化
*/
private LazySingleton() { }
/**
* 静态工厂方法,返还此类的惟一实例
*/
synchronized public static LazySingleton
getInstance()
{
if (m_instance == null)
{
m_instance = new LazySingleton();
}
return m_instance;
}
}

//由于,"双重检查成例"不可以在Java 语言中使用,懒汉式单例类,在实例化时, 必须处理好在多个线程同时首次引用此类时的访问限制问题,特别是当单例类作为资源控制器,在实例化时必然涉及资源初始化,而资源初始化很有可能耗费时间。
//饿汉式单例类可以在Java 语言内实现, 但不易在C++ 内实现,因为静态初始化在C++ 里没有固定的顺序,因而静态的m_instance 变量的初始化与类的加载顺序没有保证,可能会出问题。


参考学习:
登记式单例类

  登记式单例类是GoF 为了克服饿汉式单例类及懒汉式单例类均不可继承的缺点而设计的。本书把他们的例子翻译为Java 语言,并将它自己实例化的方式从懒汉式改为饿汉式。只是它的子类实例化的方式只能是懒汉式的, 这是无法改变的。如下图所示是登记式单例类的一个例子,图中的关系线表明,此类已将自己实例化。



  代码清单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 需要父类的帮助才能实例化。下图所示是登记式单例类子类的一个例子。图中的关系表明,此类是由父类将子类实例化的。



  下面是子类的源代码。

  代码清单4:登记式单例类的子类

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.";
}
}

  在GoF 原始的例子中,并没有getInstance() 方法,这样得到子类必须调用的getInstance(String name)方法并传入子类的名字,因此很不方便。本章在登记式单例类子类的例子里,加入了getInstance() 方法,这样做的好处是RegSingletonChild 可以通过这个方法,返还自已的实例。而这样做的缺点是,由于数据类型不同,无法在RegSingleton 提供这样一个方法。由于子类必须允许父类以构造子调用产生实例,因此,它的构造子必须是公开的。这样一来,就等于允许了以这样方式产生实例而不在父类的登记中。这是登记式单例类的一个缺点。

  GoF 曾指出,由于父类的实例必须存在才可能有子类的实例,这在有些情况下是一个浪费。这是登记式单例类的另一个缺点。



C#实现单例和多例模式:

一个单例类的实现如下所示:其中构造子私有表示子类不能被继承。



public class Singleton
  {
      private static Singleton m_instance = null;

      private Singleton()
      {
      }
      public static Singleton getInstance()
      {
        if(m_instance==null)
        {
            m_instance=new Singleton();
        }
        return m_instance;
      }
  }

一个多例类的实现如下所示:其中构造子私有表示子类不能被继承。

public class Multiton   {
      private static Multiton instance1=null;
      private static Multiton instance2=null;

      private Multiton()
      {

      }

      public static Multiton getInstance(int whichOne)
      {
        if(whichOne==1)
        {
            if(instance1==null)
            {
              instance1=new Multiton ();
            }
            return instance1;
        }
        else
        {
            if(instance2==null)
            {
              instance2=new Multiton ();
            }
          return instance2;

        }
      }
  }










Tags: singletom   单例  

类别: desinner pattern |  评论(0) |  浏览(1259) |  收藏
发表评论
看不清楚,换一张