现在的位置: 首页 > 综合 > 正文

模式学习之单例模式:Singleton

2017年05月21日 ⁄ 综合 ⁄ 共 2967字 ⁄ 字号 评论关闭

单例模式是为了作为资源管理器管理资源之用,这些资源包括:打印机,资源文件(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页,清晰的指出:“几乎没有例外,从工具类型继承是错误的”。

抱歉!评论已关闭.