單例模式

<image>

在面向對象編程中，單例模式（singleton pattern），是一種常用的創建型軟體設計模式。在應用這個模式時，單例對象的類必須保證只有一個實例存在。許多時候整個系統只需要擁有一個的全局對象，這樣有利於我們協調系統整體的行為。比如在某個伺服器程序中，該伺服器的配置資訊存放在一個文件中，這些配置數據由一個單例對象統一讀取，然後服務進程中的其他對象再通過這個單例對象獲取這些配置資訊。這種方式簡化了在複雜環境下的配置管理。

## 實現

實現單例模式的思路是：一個類能返回對象一個引用（永遠是同一個）和一個獲得該實例的方法（必須是靜態方法，通常使用getInstance這個名稱）；當我們調用這個方法時，如果類持有的引用不為空就返回這個引用，如果類保持的引用為空就創建該類的實例並將實例的引用賦予該類保持的引用；同時我們還將該類的構造函數定義為私有方法，這樣其他處的代碼就無法通過調用該類的構造函數來實例化該類的對象，只有通過該類提供的靜態方法來得到該類的唯一實例。

單例模式在多線程的應用場合下必須小心使用。如果當唯一實例尚未創建時，有兩個線程同時調用創建方法，那麼它們同時沒有檢測到唯一實例的存在，從而同時各自創建了一個實例，這樣就有兩個實例被構造出來，從而違反了單例模式中實例唯一的原則。解決這個問題的辦法是為指示類是否已經實例化的變量提供一個互斥鎖（雖然這樣會降低效率）。

通常單例模式在Java語言中，有兩種構建方式：

- 懶漢方式。指全局的單例實例在第一次被使用時構建。
- 餓漢方式。指全局的單例實例在類裝載時構建。

## 例子

### C++

下面是基於《設計模式》書中早於C++98實現的C++23實現例子：

```cpp
import std;

class Singleton {
private:
    Singleton() = default; // no public constructor
    ~Singleton() = default; // no public destructor
    inline static Singleton* instance = nullptr; // declaration class variable
    int value;
public:
    // defines a class operation that lets clients access its unique instance.
    static Singleton& getInstance() {
        if (!instance) {
            instance = new Singleton();
        }
        return instance;
    }
  
    Singleton(const Singleton&) = delete("Copy construction disabled");
    Singleton& operator=(const Singleton&) = delete("Copy assignment disabled");

    static void destroy() {
        delete instance;
        instance = nullptr;
    }

    // existing interface goes here
    [[nodiscard]]
    int getValue() const noexcept {
        return value;
    }

    void setValue(int newValue) noexcept {
        value = newValue;
    }
};

int main() {
    Singleton::getInstance().setValue(42);
    std::println("value = {}", Singleton::getInstance().getValue());
    Singleton::destroy();
}
```

程序輸入為：

```output
value=42
```

下面是Meyers所著書中單例模式的C++11實現。Meyers單例模式沒有毀壞（destruct）方法。這個程序的輸出同於上例。

```Cpp
import std;

class Singleton {
private:
    Singleton() = default;
    ~Singleton() = default;
    int value;
public:
    static Singleton& getInstance() {
        static Singleton instance;
        return instance;
    }
  
    [[nodiscard]]
    int getValue() const noexcept {
        return value;
    }
  
    void setValue(int newValue) noexcept {
        value = newValue;
    }
};

int main() {
    Singleton::getInstance().setValue(42);
    std::println("value = {}", Singleton::getInstance().getValue());
}
```

### Java

在Java中語言，單例模式（餓漢模式）應用的例子如下述代碼所示：

```java
public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
  
    // Private constructor suppresses
    // default public constructor
    private Singleton() {};
 
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
```

在Java程式語言中，單例模式（懶漢模式）應用的例子如下述代碼所示 （此種方法只能用在JDK5及以後版本（注意 INSTANCE 被聲明為 volatile），之前的版本使用「雙重檢查鎖」會發生非預期行為）：

```java
public class Singleton {
    private static volatile Singleton INSTANCE = null;
  
    // Private constructor suppresses 
    // default public constructor
    private Singleton() {};
  
    //Thread safe and performance  promote 
    public static  Singleton getInstance() {
        if(INSTANCE == null) {
            synchronized(Singleton.class) {
                // When more than two threads run into the first null check same time, 
                // to avoid instanced more than one time, it needs to be checked again.
                if(INSTANCE == null) { 
                    INSTANCE = new Singleton();
                }
            } 
        }
        return INSTANCE;
    }
}
```

### Python

Python的例子：

```python
from weakref import WeakValueDictionary
import functools

class invoke_from_class():
    def __init__(self, fn):
        self.fn = fn
        functools.update_wrapper(self, fn)
    def __get__(self, obj, objtype=None):
        self.from_class = True if obj is None else False
        return self
    def __call__(self, *args, **kwargs):
        if self.from_class is True:
            return self.fn(*args, **kwargs)

class Singleton():
    __instance = WeakValueDictionary()
    def __new__(cls, *args, **kwargs):
        if len(cls.__instance) == 0:
            obj = super().__new__(cls)
            cls.__instance[0] = obj
            cls.__init__(obj, *args, **kwargs)
        else:
            obj = cls.__instance[0]
        return obj
    @invoke_from_class
    def __init__(self, *args, **kwargs):
        for key, value in kwargs.items():
            self.__dict__[key] = value
    def __call__(self, *args, **kwargs):
        for key, value in kwargs.items():
            self.__dict__[key] = value
    @classmethod
    def clear(cls):
        if len(cls.__instance) == 1:
            del cls.__instance[0]
```

下面是其用例：

```pycon
>>> class C(Singleton):
...     def __repr__(self):
...         return (", ".join(f"{k}={v}"
...             for k, v in self.__dict__.items()))
... 
>>> c1 = C(a=1, b=2)
>>> c2 = C(a=2, b=1)
>>> assert c2 is c1
>>> c2
a=1, b=2
>>> c2(a=2, b=1)
>>> c1
a=2, b=1
>>> del c1, c2
>>> C.clear()
>>> c1 = C(a=1, b=2)
>>> c1
a=1, b=2
```

## 外部連結

- A Q&A page （java.sun.com）
- Java單例對象同步問題探討