设计模式(二)——单例模式

写单例模式,总是让我想起孔乙己写“茴香豆”的茴的四种写法,虽然感觉他比较迂腐,但是在说到单例模式时,却也是忍不住的要说单例模式也有好几种写法,这样算来,自己也算迂腐了。不过不管怎样,既然是做技术的,多掌握一点也是比较好的,同时也将积累的分享给大家,大家各凭所好吧。

 

在说“茴”字之前,需要先说下什么是“茴香豆”,也就是我们的单例模式。单例模式就是让一个对象只产生一个实例,并且对外提供一个全局的方法对其进行调用,通常来说方法名都使使用getInstance()。

 

再来说说,单例模式的整体架构。

(1)私有的构造函数

(2)私有的静态实例,该实例禁止外部访问。

(3)一个公有的静态工厂方法getInstance(),有时是需要同步的。

(4)有时也可以重写clone()方法。

 

下面,再来说说,这个“茴”字有几种写法。

第一种,饿汉式,所谓饿汉式就是主动去new一个对象,然后返回。见代码:

/**
 * 单例模式之饿汉式
 * @author xiAoT
 *
 */
public class Singleton001 {
	private static Singleton001 instance = new Singleton001();
	private Singleton001(){}
	public static Singleton001 getInstance(){
		return instance;
	}
	@Override
	protected Singleton001 clone() throws CloneNotSupportedException {
		return instance;
	}
	
}

 饿汉式的缺点是不论使不使用该类,都会在内存中实例化一个对象;优点是因为采用static类型,static本身实现了同步,所以解决了同步的问题,性能比较高,一般情况下推荐使用。

 

第二种,懒汉式,相当于延迟加载,在需要的时候再创建资源。

/**
 * 单例模式之懒汉式
 * @author xiAoT
 *
 */
public class Singleton002 {
	private static Singleton002 instance = null;
	private Singleton002(){}
	public synchronized static Singleton002 getInstance(){
		if(instance == null){
			instance = new Singleton002();
		}
		return instance;
	}
}

 由于采用了同步,在性能上会打折扣。

 

第三种,即采用缓存的方式,common.logutil中创建Log类就是采用这个方式,见LogFactory.java。基本实现方式就是用一个Map存放对象,需要使用的时候就从map中取,为了实现同步,我们一般用Hashtable存储。

/**
 * 单例模式之采用缓存
 * @author xiAoT
 *
 */
public class Singleton003 {
	private final static String CACHE_KEY = "instance";//定义一个key常量
	private Singleton003(){}
	private static Hashtable<String,Singleton003> cacheMap = new Hashtable<String, Singleton003>();
	public synchronized static Singleton003 getInstance(){
		Singleton003 instance = cacheMap.get(CACHE_KEY);
		if(instance == null){
			cacheMap.put(CACHE_KEY, instance = new Singleton003());
		}
		return instance;
	}
}

 

第四种,这个方式就神了,即可以实现延迟加载,又能够节省资源,该方式主要采用类级内部类和多线程同步缺省机制实现。

如下几种情况,JDK内部实现了同步:

1. 有static{}修饰的块或者static修改的变量初始化数据;

2. 访问final字段时

3. 在创建线程之前创建对象时

4. 线程可以看见它将要处理的对象时

/**
 * 单例模式之采用类级内部类和多线程同步缺省机制
 * @author xiAoT
 *
 */
public class Singleton004 {
	/**
	 * 类级内部类
	 * @author xiAoT
	 *
	 */
	private static class SingletonHolder{
		private static Singleton004 instance = new Singleton004();
	}
	
	private Singleton004(){}
	
	public static Singleton004 getInstance(){
		return SingletonHolder.instance;
	}
}

 类级内部类相当于外部类的成员,只有在第一次使用时才会被加载。

 

关于反序列化

如果采用了单例的类实现了序列化接口后,在进行反序列时,会自动创建新的类,为了解决这个问题,可以采用readResolve()方法

/**
 * 反序列化
 * 
 * @author xiAoT
 * 
 */
public class Singleton005 implements Serializable {
	private Singleton005() {
	}

	private static final Singleton005 INSTANCE = new Singleton005();

	public static Singleton005 getInstance() {
		return INSTANCE;
	}

	private Object readResolve() throws ObjectStreamException {
		return INSTANCE;
	}
}

 ======================================待续===============================

 

你可能感兴趣的:(单例模式,Singleton,反序列化)