模式学习之单例模式:Singleton

来源:互联网 发布:js获取页面传递的参数 编辑:程序博客网 时间:2024/05/29 18:38

单例模式是为了作为资源管理器管理资源之用,这些资源包括:打印机,资源文件(Properties)

单例模式可以分为以下几种:

1.饿汉模式(Eager Singleton)

     饿汉模式,是利用Java语言内置的static 加载模式而设计的,类实例在类加载时创建。

代码如下:

       

/** * Only once instance of the class may be created during the execution of any given program. Instances of this class should * be aquired through the getInstance() method. Notice that there are no public constructors for this class. */public class EagerSingleton {    private EagerSingleton() { }    public static EagerSingleton getInstance() {        return m_instance;    }    /** @label Creates */    private static final EagerSingleton m_instance = new EagerSingleton();}
   在这个类中,在类加载时,static 类型便开始执行初始化,这时候私有构造方法便被调用,这样,单例类的唯一实例便被创建出来。


2.懒汉模式(LazySingleton)

     懒汉模式是在类被第一次调用时被初始化,代码如下:

      

package com.javapatterns.singleton.demos;/** * Only once instance of the class may be created during the * execution of any given program. Instances of this class should * be aquired through the getInstance() method. Notice that there * are no public constructors for this class. */public class LazySingleton{    private LazySingleton() { }      synchronized public static LazySingleton getInstance()    {
      //Condition Race
    if (m_instance == null)    {        m_instance = new LazySingleton();    }    return m_instance;}    /**     * @label Creates      */    private static LazySingleton m_instance = null;}
当其他类第一次调用LazySingleton时,由于getInstance方法带synchronized 锁,所以该调用上锁后顺序执行,从而保证创建唯一单例这个复合操作的原子性。这里考虑到了多线程并发执行问题。

     其中的代码:

            

if (m_instance == null)    {        m_instance = new LazySingleton();    }
  则是一个典型的Check-then-Action的动作,也就是多线程中比较容易出现问题的Condition Race,当m_instance 没有必要的同步时,很容易出现问题。

     饿汉模式与懒汉模式,其共同点是构造方法是私有的,因此无法被继承,为了解决这个缺陷,GoF设计了登记式单例模式

3.登记模式

   

package com.javapatterns.singleton.demos;import java.util.HashMap;public class RegSingleton {    protected RegSingleton() {}    static public RegSingleton getInstance(String name)    {        if (name == null)        {            name = "com.javapatterns.singleton.demos.RegSingleton";        }        System.out.println("From RegSingleton: requesting for " + name );        if (m_registry.get(name) == null)        {            try            {                m_registry.put( name, Class.forName(name).newInstance() ) ;            }            catch(ClassNotFoundException e)            {                System.out.println("Class " + name + " is not found.");            }            catch(InstantiationException e)            {                System.out.println("Class " + name + " can not be instantiated.");            }            catch(IllegalAccessException e)            {                System.out.println("Class " + name + " can not be accessed.");            }        }        return  (RegSingleton) (m_registry.get(name) );    }    static private HashMap m_registry = new HashMap();    /**     * @label Creates     * @directed*/    /*# private RegSingletonChild lnkRegSingletonChild; */    /**     * @label Creates     * @directed     */    /*# private RegSingleton lnkRegSingleton;  */    static    {        RegSingleton x = new RegSingleton();        m_registry.put( x.getClass().getName() , x);    }    public String about()    {        return "Hello, I am RegSingleton.";    }}
  子类:

   

package com.javapatterns.singleton.demos;/** * This class is a subclass of RegSingleton */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.";    }}
   

反思:

     从面向对象的观点看,单例类一般是负责资源管理的,属于工具类。对于工具类而言,从分类学意义来看,使用继承的意义不是很大。

    《Java 与模式》中对这一块是有记录的,书中66页,清晰的指出:“几乎没有例外,从工具类型继承是错误的”。