一、引言:
单例设计模式是非常常见的一种设计模式,在java中,单例设计模式确保了每个类只有一个实例,其实现的原理是将构造方法声明为private。
二、示例代码:
下面这段代码是最佳的单例模式代码:
public class singleton{
public static void main(String[] args){
/* 调用三次,看是否只有一个对象生成 */
for(int i = 0; i < 3; i++){
Emperor emperor = Emperor.getInstance();
emperor.say();
}
}
}
class Emperor{
/* 内部构造唯一的对象 */
private static final Emperor emperor = new Emperor();
/* 构造函数private化 */
private Emperor(){
System.out.println("Constructor Emperor!");
}
/* 返回唯一对象 */
public static Emperor getInstance(){
return emperor;
}
/* 测试对象 */
public static void say(){
System.out.println("The only one Emperor is me!");
}
}
这段代码的好处在于不会在并发环境下产生多个对象,因为唯一对象是在类内部通过类加载的时候构造的,但是有时候的一些单例模式代码就会出现多个对象的情况:
public class Singleton {
private static Singleton singleton = null;
//限制产生多个对象
private Singleton(){
}
//通过该方法获得实例对象
public static Singleton getSingleton(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
这个实例中,假如线程A正在执行singleton = new Singleton();而线程B此时正好在执行
if(singleton == null)这个语句,因为对象初始化需要时间,而正好此时的对象还没有创建起来,那么线程B会继续往下执行,就会出现两个线程拥有两个对象的情况,解决的办法就是在getSingleton方法之前加上synchronized关键字,不过,对于高并发模式,显然不是最优的方式。
所以,对于java中单例模式的最佳设计如下:
public class Singleton {
private static final Singleton singleton = new Singleton();
//限制产生多个对象
private Singleton(){
}
//通过该方法获得实例对象
public static Singleton getSingleton(){
return singleton;
}
//类中其他方法,尽量是static
public static void doSomething(){
}
}
三、拓展:
1.单例模式的拓展是多例模式,就是限定产生的对象数,这里顺便说一下C/C++中的单例模式,C++也是面向对象的语言,所以,从原理上来讲,面向对象部分的单例模式和java示例如出一辙,但是C++和C中面向过程时,单例模式怎么实现的呢?答案是通过全局变量的方式,我们看一下binder中,单例模式在面向过程中的的应用:
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
gProcess = new ProcessState;
return gProcess;
}
这段代码摘自Android的binder机制,每个binder服务中,有且只有一个ProcessState用于记录当前服务的状态,上面的代码中,将描述状态的类ProcessState设为全局变量,保证了整个进程中,凡是使用到了gProcess 的地方都只有唯一的一个状态来维护。
2.java中构造方法声明为private的使用:
java中,类外部不能直接以实例化private关键字声明的构造方法的方式构造对象。
public class hello{
public static void main(String[] args){
System.out.println("hello world!");
/* 实例化对象成功,因为对应的构造是default的访问权限 */
Emperor ep = new Emperor("张三");
/* 编译报错,因为对应的构造为private权限,不能在类外调用 */
Emperor ep1 = new Emperor();
}
}
class Emperor{
/* private构造 */
private Emperor(){
System.out.println("create a Emperor class!");
}
/* default构造 */
Emperor(String name)
{
System.out.println("create a Emperor class:" + name);
}
}
博客参考书籍:秦小波 《设计模式之禅(第2版)》