您的位置:首页 > 其它

单例设计模式的几种常见实现方法

2015-06-17 16:38 806 查看
最简单的设计模式

实现方法
懒汉式

饿汉式

双重检查锁

枚举

静态内部类

单例工厂

防范

总结

最简单的设计模式

单例可以说是GOF23中最简单的一种设计模式,也经常用到。比如window的任务管理器,比如servlet对象等等。

单例要完成的就是确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个唯一的实例。就像它的定义:

Ensure a class has only one instance, and provide a global point of access to it.

最近学习整理了一下常见的单例模式实现方法(因为我见过的也不多,所以暂且认为我见过的就是常见的吧哈),大概有这么6种。

实现方法

实现单例就是要让对象在整个系统中是唯一的,不能被随意的实例化。还要考虑像线程安全问题,延迟加载问题等,就要看其具体的使用环境了。

懒汉式、饿汉式、双重检查锁、静态内部类、枚举、单例工厂和防范措施,代码放在我的github的设计模式仓库中。

话不多说,上栗子。

懒汉式

/**

* 懒汉式

* @author liu

* 类初始化时不初始化这个对象,延时加载,真要用时再加载

*/

public class SingletonDeom1 {
private static SingletonDeom1 instance;

private SingletonDeom1() {
}

//方法有同步,效率略低
public synchronized SingletonDeom1 getInstance() {
if (null == instance) {
instance = new SingletonDeom1();
return instance;
}
return instance;
}
}


饿汉式

/**

* 饿汉式

* @author liu

* 类加载时立即初始化这个对象,类加载线程安全,没有延时加载

*/

public class SingletonDemo2 {
private static SingletonDemo2 instance = new SingletonDemo2();

private SingletonDemo2() {
}

//没有同步,效率略高
public SingletonDemo2 getInstance() {
return instance;
}
}


双重检查锁

/**

* 双重检查锁

* @author liu

* 同步快在if内部,第一次同步,之后不用同步。

* JVM底层实现的问题,有时执行顺序会出问题。

* 比懒汉式略提高。

*/

public class SingletonDemo3 {
private static SingletonDemo3 instance = null;

public SingletonDemo3 getSingletonDemo3() {
if (null == instance) {
SingletonDemo3 demo = null;
synchronized(SingletonDemo3.class) {
demo = instance;
if (null == demo) {
synchronized(SingletonDemo3.class) {
if (null == demo) {
demo = new SingletonDemo3();
}
}
}
instance = demo;
}
}
return instance;
}

private SingletonDemo3() {

}
}


枚举

/**
* JVM保障枚举单例和线程安全,但无延时加载。
* @author liu
*
*/
public enum SingletonDemo5 {
INSTANCE;

public void function() {

}
}


是JVM直接罩着的,用起来比较方便。

静态内部类

/**
* 静态内部类形式
* @author liu
* 不会立即加载,调用get才会加载内部类,加载类是线程安全的,延时加载又线程安全。
*/
public class SingletonDemo4 {
private SingletonDemo4() {

}

private static class Instance {
private static final SingletonDemo4 instance = new SingletonDemo4();
}

public SingletonDemo4 getSingletonDemo4() {
return Instance.instance;
}
}


加强版懒汉式,是比较好用的一种。

单例工厂

/**
* 单例类
* @author liu
* 要创建这个单例类的单例对象
*/
public class SingletonDemo7_1 {
private SingletonDemo7_1() {

}
public void doSomething() {
System.out.println("开始干活");
}
}

/**
* 用工厂方法实现单例
* @author liu
* 当然要通过正常的渠道,其他类通过反射也是可以获得单例类的其他对象的。
*/
public class SingletonDemo7_2 {
private static SingletonDemo7_1 demo7_1;

static{
try {
Class clazz = Class.forName(SingletonDemo7_1.class.getName());
Constructor<SingletonDemo7_1> constructor = clazz.getEnclosingConstructor();
constructor.setAccessible(true);
demo7_1 = constructor.newInstance();
} catch(Exception e) {
System.out.println("报错");
}
}

public SingletonDemo7_1 getSingletonDemo7_1() {
return demo7_1;
}
}


借助了工厂模式,单例工厂只产生同一个单例对象。

防范

如果是架构级的,还要考虑防范通过非正常渠道,比如反射、反序列化方法获取对象,以懒汉式为例。

/**
* 防止反射和反序列化破坏
* @author liu
*
*/
public class SingletonDemo6 {
private static SingletonDemo6 instance = null;

//反射时设置setAccessible跳过权限,调用构造器,若instance对象不为空,则抛出异常。
private SingletonDemo6() {
if (instance != null) {
throw new RuntimeException();
}
}

//反序列化时,有readResolve方法,则直接返回此方法指定的对象,而不创建新的对象。
private Object readResolve() {
return instance;
}

public synchronized SingletonDemo6 getSingletonDemo6() {
if (null == instance) {
instance = new SingletonDemo6();
}
return instance;
}
}


总结

当全局只需要一个且只能有一个对象的时候就用单例喽。简单说就是通过构造方法的私有化,不让别人随意创建新的对象,而是用自己创建好的唯一的对象提供给对象的调用者。

至于对是否延迟加载、线程安全和特殊情况的防范,就要看使用的具体环境了。当然,如果需要的话也可以从单例模式扩展为多例。

最后

thanks for 《设计模式之禅》(秦小波 著)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  设计模式 单例 实例