首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

枚举门类实现的单例模式(转)

2012-10-09 
枚举类型实现的单例模式(转)我们常用的构造单例模式(Singleton)的方法,一般有2种 1 提供一个静态的公共属

枚举类型实现的单例模式(转)
我们常用的构造单例模式(Singleton)的方法,一般有2种

1 提供一个静态的公共属性
2 提供一个静态的公共方法

这2个方法,都是采用了私有的构造器来防止外部直接构造实例。 但我们可以用反射的方法,获得多个实例。后面我会给出测试的代码。

从1.5开始,枚举也可以用来获得单例,而且更加可靠。同时又自动提供了一些额外的功能。

先看看测试代码:

import java.lang.reflect.Constructor;  
/** 
* 测试Singleton的可靠性。 
*  
* @author 老紫竹(laozizhu.com) 
*/ 
public class TestSingleton {  
  public static void main(String[] args) {  
    testSingleton1();  
    testSingleton2();  
    testSingleton3();  
  }  
  public static void testSingleton1() {  
    try {  
      // 测试Singletom1  
      // 拿到第一个实例  
      TestSingleton1 s1 = TestSingleton1.getInstance();  
      // 测试拿到第二个实例  
      Class c1 = Class.forName("TestSingleton1");  
      Constructor[] cons = c1.getDeclaredConstructors();  
      Constructor cc1 = cons[0];  
      cc1.setAccessible(true);  
      TestSingleton1 s2 = (TestSingleton1) cc1.newInstance(null);  
      System.out.println(s1 + "/" + s2);  
      System.out.println(s1 == s2);  
    } catch (Exception ex) {  
      ex.printStackTrace();  
    }  
  }  
  public static void testSingleton2() {  
    try {  
      // 测试Singletom1  
      // 拿到第一个实例  
      TestSingleton2 s1 = TestSingleton2.getInstance();  
      // 测试拿到第二个实例  
      Class c1 = Class.forName("TestSingleton2");  
      Constructor[] cons = c1.getDeclaredConstructors();  
      Constructor cc1 = cons[0];  
      cc1.setAccessible(true);  
      TestSingleton2 s2 = (TestSingleton2) cc1.newInstance(null);  
      System.out.println(s1 + "/" + s2);  
      System.out.println(s1 == s2);  
    } catch (Exception ex) {  
      ex.printStackTrace();  
    }  
  }  
  public static void testSingleton3() {  
    try {  
      // 测试Singletom1  
      // 拿到第一个实例  
      TestSingleton3 s1 = TestSingleton3.getInstance();  
      // 测试拿到第二个实例  
      Class c1 = Class.forName("TestSingleton3");  
      Constructor[] cons = c1.getDeclaredConstructors();  
      Constructor cc1 = cons[0];  
      cc1.setAccessible(true);  
      TestSingleton3 s2 = (TestSingleton3) cc1.newInstance(null);  
      System.out.println(s1 + "/" + s2);  
      System.out.println(s1 == s2);  
    } catch (Exception ex) {  
      ex.printStackTrace();  
    }  
  }  
}  
/** 
* 一个普通的Singletone实现。 
*  
* @author 老紫竹(laozizhu.com) 
*/ 
class TestSingleton1 {  
  private static final TestSingleton1 INSTANCE = new TestSingleton1();  
  public static TestSingleton1 getInstance() {  
    return INSTANCE;  
  }  
  private TestSingleton1() {  
  }  
}  
/** 
* 一个用异常强化了的Singletone实现。 
*  
* @author 老紫竹(laozizhu.com) 
*/ 
class TestSingleton2 {  
  private static final TestSingleton2 INSTANCE = new TestSingleton2();  
  public static TestSingleton2 getInstance() {  
    return INSTANCE;  
  }  
  private static boolean initSign;  
  private TestSingleton2() {  
    if (initSign) {  
      throw new RuntimeException("实例只能建造一次");  
    }  
    initSign = true;  
  }  
}  
/** 
* 枚举实现的Singleton 
*  
* @author 老紫竹(laozizhu.com) 
*/ 
enum TestSingleton3 {  
  INSTANCE;  
  public static TestSingleton3 getInstance() {  
    return INSTANCE;  
  }  
}




测试结果
TestSingleton1@c17164/TestSingleton1@1fb8ee3
false
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at TestSingleton.testSingleton2(TestSingleton.java:43)
at TestSingleton.main(TestSingleton.java:11)
Caused by: java.lang.RuntimeException: 实例只能建造一次
at TestSingleton2.<init>(TestSingleton.java:103)
... 6 more
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Constructor.java:511)
at TestSingleton.testSingleton3(TestSingleton.java:61)
at TestSingleton.main(TestSingleton.java:12)


小结:可见,只有第三种枚举的方法才是最安全的。

关于里面提到的,在序列化是可能出现的问题,我看以后在讨论吧。不过因为枚举实现的单例没有这个问题,所以我看以后就用枚举好了,何必自己跟自己过不去呢?

热点排行