在实际开发中,单例模式是一种很有用的设计模式,能很好的解决我们只需要类的一个实例的情况,单例模式常见的两种实现方式如下
懒汉式:
class Test {
private static Test _instance;
private Test() {
}
/**
*
* @return 返回Test唯一实例
*/
public synchronized static Test getInstance() {
if (null == _instance) {
_instance = new Test();
}
return _instance;
}
}
饿汉式:
class Test {
private static Test _instance = new Test();
private Test() {
}
/**
*
* @return 返回Test唯一实例
*/
public static Test getInstance() {
return _instance;
}
}
按照上面这种写法,几乎所有单例都需要这段基本一样的代码,本文将介绍另外一种实现,可实现代码的复用,实现技巧:将单例看成是一种性质,而JDK1.5+的注解这一特性能很好的帮助我们解决这一需求,将类标记为单例。
1. 首先定义单例注解,注解的作用就是将类标记为单例
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 单例注解,该注解只能作用在类上,不能作用在方法上
*/
@Target({ java.lang.annotation.ElementType.ANNOTATION_TYPE, java.lang.annotation.ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Singleton {
}
2. 定义对象工厂,用于解释我们的注解,并提供获取单例对象的方法
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
/**
*
* 对象工厂,用于解释我们的单例注解,并提供获取单例对象的方法
*
* @author xxx
* @version 2014-4-14
*/
public final class New {
/**
* container to save Singleton
*/
private static volatile Map<String, Object> objs = new HashMap<String, Object>();
/**
* 返回单例的静态方法,如果类没有用Singleton注解标记,则返回一个全新的实例
* 关于该方法线程安全
* @param clazz
* @return the Singleton
*/
public static <T> T getInstance(Class<T> clazz) {
String className = clazz.getName();
synchronized (clazz) {
/**
* whether used the Single Annotation
*/
if (clazz.isAnnotationPresent(Singleton.class)) {
Object object = objs.get(className);
if (object == null) {
objs.put(className, newInstance(clazz));
}
return clazz.cast(objs.get(className));
}
return newInstance(clazz);
}
}
private static <T> T newInstance(Class<T> clazz) {
try {
Constructor<T> constructor = clazz.getDeclaredConstructor();
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return constructor.newInstance();
} catch (Exception e) {
throw new NewInstanceException(e);
}
}
}
class NewInstanceException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
public NewInstanceException() {
super();
}
public NewInstanceException(String message, Throwable cause) {
super(message, cause);
}
public NewInstanceException(String message) {
super(message);
}
public NewInstanceException(Throwable cause) {
super(cause);
}
}
注:单例类,不能包含带参数构造方法,而对于无参构造函数是否公有物要求
至此,我的基于反射机制的单例模式核心代码,已经实现完毕。
测试代码:
public class Main {
public static void main(String[] args) {
Test instance1 = New.getInstance(Test.class);
Test instance2 = New.getInstance(Test.class);
System.out.println(instance1.hashCode() == instance2.hashCode());
}
}
@Singleton
class Test {
private Test() {
}
}