现在的位置: 首页 > 综合 > 正文

每天一个设计模式之Singleton

2012年07月25日 ⁄ 综合 ⁄ 共 2812字 ⁄ 字号 评论关闭

Link:

http://www.oodesign.com/

 

Singleton

属于Creational Design Patterns

顾名思义,就是只能有一个实例的类。这是最容易理解的一个设计模式。

Usually singletons are used for centralized management of internal or external resources and they provide a global point of access to themselves.

Singleton pattern should be used when we must ensure that only one instance of a class is created and when the instance must be available through all the code. A special care should be taken in multithreading environments when multible threads must access
the same resources throught the same singleton object.

 

Common usage

There are many common situations when singleton pattern is used:
- Logger Classes

- Configuration Classes
- Accesing resources in shared mode

具体说明请看原文。

如何实现:

The implementation involves a static member in the "Singleton" class, a private constructor and a static public method that returns a reference to the static member.

class Singleton
{
private static Singleton instance;
private Singleton()
{
...
}
 
public static synchronized Singleton getInstance()
{
if (instance == null)
instance = new Singleton();
 
return instance;
}
...
public void doSomething()
{
... 
}
} 

通过调用静态对象(实例)的方法

Singleton.getInstance().doSomething(); to provide a global point of access to the object.
注意这里的synchronized。用于多线程中的操作。但是这个例子并不好,因为一般来说只需要在未创建实例前不允许多线程检查并创建实例。在已经创建实例后,可以异步get实例。文章后面会对这个问题做解释。
这样,将实例放入static member。其他代码就不能调用构造函数来创建实例,只能通过一个public方法来取回静态成员变量(实例)。

比如在log4j中就有一个典型应用:

Logger consoleLogger = Logger.getLogger(KillScript.class);

getLogger方法会返回一个名为KillScript.class的logger。如果这个logger在其他地方已经被创建了,则返回实例。在代码中的任何一个地方都可以调用这个logger,且是同一个实例。

观察log4j中logger代码就会发现:

1,构造函数是protected。

protected Logger(String name) {
    super(name);
  }

2,public getLogger用于取回logger实例。当然取回的实例是LogManager生成的,相对复杂一些。

实际上在一个程序中provide a global logging access是很合理的要求。

所以这个模式的特点是:

1,仅这个类自己就搞定了。不像其他很多模式,为了灵活性必须引入其他的附加类。

2,构造函数是private,以防止代码随意实例化类。

3,存在一个静态成员变量,类型是这个类本身。用于存储唯一被实例化出来的那个对象。毫无疑问为了我们的目的,这个静态变量也是private。

4,存在一个getInstance方法给外部代码使用。很明显它必须是public的。同时,由于在没有实例对象时,需要用这个方式取得对象,这个方法必须是static的。

 

Lazy instantiation 和 Early instantiation。

前一个意思是只有在需要使用实例时才创建实例。another one means singleton object is instantiated when the class is loaded and not when it is first used, due to the fact that the instance member is declared static。即在构造函数中实例化。

Lazy instantiation 的问题在于必须处理多线程的问题,同步的方法就是前面代码里在getInstant()前的synchronized,而Early instantiation则不需要。

同步的效率问题

正如前面所说,对getInstance同步是一种浪费。

In other words, once we’ve set the uniqueInstance variable to an instance of Singleton, we have no further need to synchronize this method.

因此对考虑多线程时的单体模式时,给出了如下意见:

1,如果效率不是什么大问题,那么就使用同步getInstance().

2, 或使用early instantiation.如下:

public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
}

3,如果都不行,那个就使用“double-checked locking”

public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}

抱歉!评论已关闭.