了解设计模式 之 创建模式(四) -- 单例模式

4. 单例模式(Singleton Pattern)

单例模式顾名思义,就是实现了单例,保证了在一个应用中只存在某个类的唯一实例。

单例模式包括3个变种:饿汉式,懒汉式和登记式。下边来一一的说明

(1) 饿汉式单例

public class EagerSingleton {

// 单例
private static final EagerSingleton instance = new EagerSingleton();

private EagerSingleton() {
// 构造函数设成private保证不能通过它去实例化
}

public static EagerSingleton getInstance() {
return instance;
}
}


此种方式在类被加载时就已经初始化了instance,所以称之为饿汉式。

但是,这种方式有个弱点,就是构造函数是私有的,也就是说这个类是无法继承的。

(2) 懒汉式单例

public class LazySingleton {
private static LazySingleton instance = null;

private LazySingleton() {
}

public synchronized static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}


这个方式只在需要实例化的时候才去真正的实例化instance变量,在资源使用的效率上是比饿汉式要高的,但是它的构造函数同样是私有的,也无法继承此类。

另外,还有一个需要说明的地方,#getInstance()方法有很多人是推荐使用"双重检查锁定(DCL, double check locking)"这种方式去实现的,这样就不需要对整个方法来"synchronized"了,节省系统的开销。但是,由于Java的内存模型的原因,会导致"无序写入"问题,进而使DCL失效。但是,对于双重检查锁定,也是有补救的方法的,《Head First Design Pattern》中就提到了使用"volatile"关键字的方法,不过这个方法要在JDK1.5以上才生效,具体的代码如下:

public class LazySingleton {
// 使用"volatile"
private static volatile LazySingleton instance = null;

private LazySingleton() {
}

// 使用DCL
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
if (instance == null) {
instance = new LazySingleton();
}
}

}
return instance;
}
}


(3) 登记式单例

登记式单例克服了饿汉式和懒汉式单例都无法继承的缺点,实现的代码如下所示:

public class RegisterSingleton {
private static Map<String, RegisterSingleton> registry = new HashMap<String, RegisterSingleton>();
static {
RegisterSingleton x = new RegisterSingleton();
registry.put(x.getClass().getName(), x);
}

protected RegisterSingleton() {
}

public static RegisterSingleton getInstance(String name) {
if (name == null) {
name = RegisterSingleton.class.getName();
}
if (registry.get(name) == null) {
try {
registry.put(name, (RegisterSingleton) Class.forName(name).newInstance());
} catch (Exception e) {
System.out.println("Error happened.");
}
}
return registry.get(name);
}
}


这样,RegisterSingleton的子类就可以实现单例了,代码如下:

public class SubRegisterSingleton extends RegisterSingleton {
public SubRegisterSingleton() {
}

public static SubRegisterSingleton getInstance() {
return (SubRegisterSingleton) RegisterSingleton.getInstance(SubRegisterSingleton.class.getName());
}
}


这里,您可能会注意到,SubRegisterSingleton的构造函数是public的,因为在SubRegisterSingleton的父类RegisterSingleton需要实例化一个SubRegisterSingleton的对象,所以,这个构造函数必须是public的,但是,这里也会出现客户端直接使用这个构造函数去构造对象的问题,这个是登记式单例的一个弱点。另外,子类的单例实现是一定要父类来参与的,这个也有点浪费资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值