登记式单态类 登记式单态类是GoF为了克服饿汉式单态类及懒汉式式单态类均不可继承的缺点而设计的 作者把他们的例子翻译为爪哇语言并将它自己实例化的方式从懒汉式改为饿汉式只是它的 子类实例化的方式只能是懒汉式的这是无法改变的 图 登记式单态类的一个例子 图中的关系线表明此类自已将自己实例化 package comjavapatternssingletondemos; import javautilHashMap; public class RegSingleton { protected RegSingleton() {} static public RegSingleton getInstance(String name) { if (name == null) { name = comjavapatternssingletondemosRegSingleton; } if (m_registryget(name) == null) { try { m_registryput( name ClassforName(name)newInstance() ) ; } catch(Exception e) { Systemoutprintln(Error happened); } } return (RegSingleton) (m_registryget(name) ); } static private HashMap m_registry = new HashMap(); static { RegSingleton x = new RegSingleton(); m_registryput( xgetClass()getName() x); } public String about() { return Hello I am RegSingleton; } } 代码清单 登记式单态类(注意为简单起见这里没有考虑多线程访问限制的问题读者可自行加入一个有双重 检查的访问限制) 它的子类 图 登记式单态类子类的一个例子 图中的关系线表明此类是由父类将自己实例化的 package comjavapatternssingletondemos; import javautilHashMap; public class RegSingletonChild extends RegSingleton { public RegSingletonChild() {} static public RegSingletonChild getInstance() { return (RegSingletonChild) RegSingletongetInstance( comjavapatternssingletondemosRegSingletonChild ); } public String about() { return Hello I am RegSingletonChild; } } 代码清单 登记式单态类的子类 在GoF原始的例子中并没有getInstance()方法这样得到子类必须调用文类的getInstance(String name) 方法并传入子类的名字很不方便 作者在登记式单态类子类的例子里加入了getInstance()方法这样做的好处是RegSingletonChild 可以通过这个方法返还自已的实例而这样做的缺点是由于数据类型不同无法在RegSingleton提供 这样一个方法 由于子类必须充许父类以构造子调用产生实例因此它的构造子必须是公开的这样一来就等于允许了 以这样方式产生实例而不在父类的登记中这是登记式单态类的一个缺点 GoF曾指出由于父类的实例必须存在才可能有子类的实例这在有些情况下是一个浪费 这是登记式单态类的另一个缺点 爪哇语言里的垃圾回收 爪哇语言里垃圾回收使得单态类的使用变得有点复杂原因就在于JDK版里加进去的类的自动清除 这种类的垃圾回收会清除掉类本身而不仅仅是对象!事实上JDK甚至可以清除掉一些系统类! 在JDKx版本里类的自动清除尚未加入 在JDK及以后的版本里升阳公司又收紧了类的垃圾回收规则它规定所有通过局部的和系统的 类加载器加载的类永不被回收并且通过其它类加载器加载的类只有在加载器自己被回收后才可被回收 在版JDK里使用单态类的读者如果不了解这一版爪哇语言的特点很有可能会遇到类消失掉的奇特问题 为了使你的单态类能在所有版本的爪哇环境里使用作者特别提供一个看守类程序它能保证你的单态类 甚至其它任何对象一旦交给看守对象即不会莫名其妙地被垃圾回收器回收直到你把它从看守 那里把它释放出来 图 看守类的一个例子 package comjavapatternssingletondemos; import javautilVector; /** * This class keeps your objects from garbage collected */ public class ObjectKeeper extends Thread { private ObjectKeeper() { new Thread(this)start(); } public void run() { try { join(); } catch (InterruptedException e) {} } /** * Any object passed here will be kept until you call discardObject() */ public static void keepObject(Object myObject) { Systemoutprintln( Total number of kept objects: + m_keptObjectssize()); m_keptObjectsadd(myObject); Systemoutprintln( Total number of kept objects: + m_keptObjectssize()); } /** * This method will remove the protect of the object you pass in and make it * available for Garbage Collector to collect */ public static void discardObject(Object myObject) { Systemoutprintln( Total number of kept objects: + m_keptObjectssize()); m_keptObjectsremove(myObject); Systemoutprintln( Total number of kept objects: + m_keptObjectssize()); } private static ObjectKeeper m_keeper = new ObjectKeeper(); private static Vector m_keptObjects = new Vector(); } 代码清单 看守类的一个实现 看守类应当自我实例化而且在每个系统里只需一个实例这就意味着看守类本身就应当是单态类当然类 消失的事情绝不可以发生在它自己身上作者提供的例子刚好满足所有的要求 一个实用的例子 这里作者给出一个读取属性(properties)文件的单态类作为单态类的一个实用的例子 属性文件如同老式的视窗编程时的ini文件属于系统的资源而读取属性文件即为资源管理 显然应当由一个单态类负责 图 这个例子的UML 显然在大多数的系统中都会涉及属性文件的读取问题因而这个例子非常有实用价值 在这个例子里作者假定需要读取的属性文件就在当前目录中且名为singletonproperties 在这个文件中有如下的一些属性项 em=How em=are em=you em=doing em=? 代码清单 属性文件内容 本例子的源代码如下 package comjavapatternssingletondemos; import javautilProperties; import javaioFileInputStream; import javaioFile; public class ConfigManager { /** * 私有的构造子 用以保证实例化的唯一性 */ private ConfigManager() { m_file = new File(PFILE); m_lastModifiedTime = m_filelastModified(); if(m_lastModifiedTime == ) { Systemerrprintln(PFILE + file does not exist!); } m_props = new Properties(); try { m_propsload(new FileInputStream(PFILE)); } catch(Exception e) { eprintStackTrace(); } } /** * * @return 返还ConfigManager类的单一实例 */ synchronized public static ConfigManager getInstance() { return m_instance; } /** * 读取一特定的属性项 * * @param name 属性项的项名 * @param defaultVal 属性项的缺省值 * @return 属性项的值(如此项存在) 缺省值(如此项不存在) */ final public Object getConfigItem(String name Object defaultVal) { long newTime = m_filelastModified(); // 检查属性文件是否被其它程序(多数情况是程序员手动)修改过 // 如果是重新读取此文件 if(newTime == ) { // 属性文件不存在 if(m_lastModifiedTime == ) { Systemerrprintln(PFILE + file does not exist!); } else { Systemerrprintln(PFILE + file was deleted!!); } return defaultVal; } else if(newTime > m_lastModifiedTime) { m_propsclear |