设计模式初探-单例模式

2014-11-24 07:20:22 · 作者: · 浏览: 0

Singleton模式,又称单例模式,它保证一个类仅有一个实例,并提供一个访问它的全局访问点。单例模式在平常开发中经常用到,比如系统的全局配置属性,常用的工具类或工厂方法都可以实现为一个单例。单例模式概念很简单,实现起来也不麻烦,但一不小心还是有可能出错的。

一、使用场景

只要是要求实例唯一的都可以使用单例模式来实现,特别是耗资源的实例!

二、UML图

单例模式uml图

三、Java实现

1、懒汉型

package study.patterns.singleton;
/**
 * 单例模式:根据实例创建的时机与方式可分为
 * 懒汉型,饿汉型,双重检测型等
 * @author qbg
 * 
 */
public class Singleton {
	private static Singleton instance = null;
	/*
	 * 限制客户自己生成类实例的能力,不过通过java反射机制可以突破此限制
	 */
	/**
	 * 为用户提供统一的获取类实例的接口,
	 * 此接口可以根据需求改变实现,即可以保持类实例的唯一,
	 * 也可以维持多个类实例,这对用户来说是透明的。
	 * @return
	 */
	public static synchronized Singleton getInstance(){
		if(instance==null){
			instance = new Singleton();
		}
		return instance;
	}
}
通过将instance暴露为public的静态的类属性也可以实现单例模式,但较工厂方法相比缺少灵活性,比如后期单例变多例。同时,由于静态类属性是通过类加载器保证实例的唯一性(instance在类装载时才会实例化),而类装载的时机有很多种,导致对实例的创建缺乏掌控。

懒汉型单例由于延迟了类实例的创建,只在真正需要时才创建,所以较饿汉型更适用,当然如果不需要考虑实例的懒加载那就无所谓了。对于耗资源,费时间的实例创建最好采用懒汉形式实现。

2、饿汉型

package study.patterns.singleton;
/**
 * 单例模式:根据实例创建的时机与方式可分为
 * 懒汉型,饿汉型,双重检测型等
 * @author qbg
 * 
 */
public class Singleton {
	/**
	 * 这种方式基于classloder机制避免了多线程的同步问题,
	 * 不过,instance在类装载时就实例化,而导致类装载的原因有很多种。
	 * 在单例模式中大多数都是调用getInstance方法, 但不排除其他方式(比如调用其他的静态方法)导致类装载。
	 */
	private static Singleton instance = new Singleton();
	/*
	 * 限制客户自己生成类实例的能力,不过通过java反射机制可以突破此限制
	 */
	private Singleton(){}
	/**
	 * 为用户提供统一的获取类实例的接口,
	 * 此接口可以根据需求改变实现,即可以保持类实例的唯一,
	 * 也可以维持多个类实例,这对用户来说是透明的。
	 * 由于类加载器机制避免线程同步问题,所以此处不需要再同步了
	 * @return
	 */
	public static Singleton getInstance(){
		return instance;
	}
}

3、双重检测型

package study.patterns.singleton;
/**
 * 单例模式:根据实例创建的时机与方式可分为
 * 懒汉型,饿汉型,双重检测型等
 * @author qbg
 * 
 */
public class Singleton {
	private static Singleton instance = null;
	/*
	 * 限制客户自己生成类实例的能力,不过通过java反射机制可以突破此限制
	 */
	/**
	 * 双重检测机制,确保懒加载又提高了性能。
	 * @return
	 */
	public static Singleton getInstance(){
		//先判断实例是否创建好了,如果好了直接返回
		if(instance == null){
			//如果实例没有创建好则同步实例创建过程.
			synchronized (Singleton.class) {
				if(instance==null){
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
}
双重检测机制由于将同步过程最小化,且尽可能的减少同步次数,从而提高了性能。第一种实现方式每次通过getInstance()获取实例都需要同步,而这些同步只需在实例创建时才有用,大大浪费资源。不过双重检测机制在java 1.5后才能表现正确的行为,参考http://www.ibm.com/developerworks/cn/java/j-dcl. html

4、枚举型

package study.patterns.singleton;
/**
 * 利用java 1.5提供的枚举类型实现单例。
 * 此方式较其他实现方式更简洁,由于枚举无偿地提供序列化机制,
 * 绝对防止多次实例化,即使是在面向复杂的序列化或反射攻击的时候。
 * 不过这种方式只能在java 1.5后使用.
 * @author qbg
 */
public enum Singleton {
	INSTANCE;
	public void doSomething(){}
}

四、模式优缺点

优点:

1、对唯一实例的受控访问,由于Singleton类将实例的个数及产生时间都封装了起来,而不是让客户自己生成,所以它严格的控制了客户怎样及何时访问实例。

2、缩小命名空间,单例模式是对全局变量的一种改进,减少了对命名空间的污染。对于java没多大用途,java里没全局变量的概念。

3、允许可变数目的实例,这个需要实现为工厂方法,静态实例的单例模式限制只能生成1个实例。