Java 设计模式:扩展Singleton

1、登记式单例类(RegSingleton)

登记式单例类是为了克服普通单例模式不可继承的特点而设计的。
登记式单例类的源代码如下:(一下代码均经过测试)
//RegSingleton.java :登记式单例父类
package com.javapatterns.singleton.demos;
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)
   {
    e.printStackTrace();
   }
  }
  return (RegSingleton)(m_registry.get(name));
 }
 //一个示意性的商业方法
 public String about()
 {
  return "Hello,I am RegSingleton.";
 }
}

//RegSingletonChild.java :登记式单例的子类
package com.javapatterns.singleton.demos;
import java.util.*;

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";
 }
}
子类RegSingleytonChild需要父类的帮助才能产生对象,由于子类必须允许父类以构造函数调用产生对象,因此,它的构造函数必须是公开的。这样一来就等于允许以这样方式产生实例而不是在父类的登记中,这是登记式单例的一个缺点。
GOF曾指出,由于父类的实例必须存在才可能有子类的实例,这在有些情况下是一个浪费。这是登记式单例类的另一缺点。

 

在什么情况下使用单例模式:

使用条件:
在一个系统要求一个类只有一个实例时才应当使用单例模式。
切记:试图使用单例模式管理共享资源的声明周期,这是不恰当的。

单例模式的加载器问题:

class singleton
{
 private singleton() {}//构造函数必须是私有的,防止外部调用,生成对象
 
 private static final singleton aobject = new singleton();//该类的唯一对象
 
  /*
    返回改类的唯一一个对象,你仔细想想,是不是只有通过这个方法可以获
 得这个类的对象
  */
  public static singleton getInstance()
  {
 return aobject;
  }
 
  public void write()
  {
   System.out.println("*****************");
  }
 
  public static void main(String[] args)
  {
   try
   {
    singleton obj1 = (singleton)Class.forName("singleton").newInstance();
    singleton obj2 = (singleton)Class.forName("singleton").newInstance();
    System.out.println(obj1);
    System.out.println(obj2); 
   }
   catch(Exception e)
   {
    e.printStackTrace();
   }
   
  }
}
测试结果如下:


singleton@7259da

singleton@16930e2


这说明同一个JVM中会有多个类加载器时,当两个加载器同时加载同一个类时,会出现两个实例。在很多J2EE服务器允许同一个服务器内有多个Servlet引擎时,每一个引擎都有独立的类加载器,经由不同的类加载器加载的对象之间是绝缘的。
除非系统有协调机制,不然在这中情况下应当尽量比避免使用有状态的单例类。

JDK中的单例模式:(有兴趣的话可以查阅jdk的源代码,在jdk的安装目录下src.zip包中)

Java语言中有很多单例模式的应用实例:
Java的Runtime对象
在java内部,java.lang.Runtime对象就是一个使用单例模式的例子,每一个java应用里面,都有一个Runtime对象,通过这个对象,应用程序可以与其运行环境发生相互作用。Runtime类提供一个静态工厂方法getRuntime();
Introspector类(在调试JavaBean的BDK中使用的)
java.awt.Toolkit类,getDefaultToolkit()方法就是一个静态的方法。

 


2、不完全的单例类


package com.javapatterns.singleton.demos;

public class LazySingleton
{
 private static LazySingleton m_instance = null;
 
 //公开的构造方法,外界可以直接实例化
 public LazySingleton()
 {
  
 }
 /**
  *静态工厂方法
  */
 synchronized public static LazySingleton getInstance()
 {
  if(m_instance==null)
  {
   m_instance=new LazySingleton();
  }
  return m_instance;
 }
}
以上代码和以前的代码不同之处在于,其构造函数是public的,由于外界可以通过该构造函数创建出任意个此类的对象,这违背了单例类只能有一个实例的特性,因此这个类不是完全的单例类。这种情况有时会出现,如:javax.swing.TimerQueue便是一例。
造成这种情况出现的原因:
(1)初学者的错误。许多初学者没有认识到单例的构造函数不能是公开的,因此犯下这个错误。(看来我的错误还严重,以前我竟不知道构造函数还可以是私有的,唉!悲哀啊!)
(2)当初由于考虑不周,将一个类设计成为单例类,后来发现此类应当有多于一个的实例。为弥补错误,干脆将构造函数改为公开的,以便在需要时,随时调用构造函数创建新的实例。(看来我该检讨了)
(3)设计师的java知识很好,而且也知道单例模式的正确使用方法,但是,还是有意使用这种不完全的单例模式,因为他在意使用一种“改良”的单例模式。此时,出去共有的构在函数之外,这个类必须是很好的单例模式才可以。(我的境界太低了,永远到不了,大家如果自信的话,就试试吧!男人要稳!)

至此,单例模式就结束了,我的手要抽筋了,说实话大部分是抄书《java与模式》,感谢作者阎宏博士。虽然是抄书,但是全是我读过,亲手打出来,并且部分代码是我理解后改写的。(为了初学者的易读性考虑),部分改写也许有偏差请不吝赐教,多谢多谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值