最近项目组开始找人,试卷上豁然是个经典的问题(话说我毕业那会儿都已经是老题目,如今还在用)那就是,
哥们儿,写个单例模式吧!
恰巧今天早上看《effective java》看到单例模式的一种新写法。就再次分享给大家。希望对大家有用。
单例模式,是最简单的设计模式(之一?),单例对象的类必须保证只有一个实例存在。
方法1.
public class SingletonClass {
/**
* (1)私有而且是static的实例,在加载类的时候直接初始化该实例
*/
private static final SingletonClass singletonInstance = new SingletonClass();
/**
* (2)私有构造器,防止有人new该对象
*/
private SingletonClass() {
}
/**
* (3)外部获取实例的唯一接口方式
* @return
*/
public static SingletonClass newSingletonInstance() {
return singletonInstance;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(">>" + i + "=" + SingletonClass.newSingletonInstance());
}
}
}
特别需要注意注释部分,基本是环环相扣的。
(1)私有的,所以外部无法直接引用,又是static的,所以在没有初始化时是可以调用的,这为下面一步做了铺垫
(2)私有构造器,所以外部无法直接通过new的方式来创建对象
(3)通过静态方法来给出单例对象,这种方法封装了具体初始化对象的方法,就可以“动点手脚”,这里是将类持有的单例对象暴露出去。
方法2.
public class SingletonClass {
/**
* 私有而且是static的实例
*/
private static final SingletonClass singletonInstance = null;
/**
* 私有构造器,防止有人new该对象
*/
private SingletonClass() {
}
/**
* 外部获取实例的唯一接口方式
* @return
*/
public static SingletonClass newSingletonInstance() {
//第一次调用时初始化
if (singletonInstance == null) {
singletonInstance = new SingletonClass();
}
return singletonInstance;
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(">>" + i + "=" + SingletonClass.newSingletonInstance());
}
}
}
看起来,方法1和方法2的方式区别不大,实际上, 如果是初始化需要耗费的资源较多或者该类很少被使用,那么在加载类时是不合适的,选择方法2会比较好。
另外,同事今天提到,如果在并发时,这段代码是有问题的
<span style="white-space:pre"> </span>//第一次调用时初始化
if (singletonInstance == null) {
singletonInstance = new SingletonClass();
}
如果遇到并发,会实例化不止一个实例,解决方案就是解决并发的方案,最简单就是在newSingletonInstance()
上加synchronized。
方法3.
public enum SingletonClass {
singletonInstance;
private String name = "sig";
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println(">>" + i + "=" + SingletonClass.singletonInstance.name);
}
}
}
这种方法是利用枚举的特性来实现的。实际上,枚举最终还是会被翻译成final static的。
可以参考这篇文章单例模式中为什么用枚举更好,说的比较详细。
综上所述,单例模式作为一种设计模式,可以有多种实现方式,各种方式都是利用语言的某些特性来具体实现。如此,下次学习一个新的语言的时候可以考虑尝试写一个单例。
还稍微想了下,如果需要的是双例呢?可以试试看,看你理解了没?