今天在找單例設計模式(Singleton design pattern)或稱單例模式(Singleton Pattern)的名詞解釋資料時,找到了一篇「How to use the Singleton design pattern」。

該作者使用簡短的描述、簡潔的範例,清楚的闡明單例設計模式的概念與使用方式,我覺得這篇文章很容易懂,很值得參考,因此將其翻譯成中文,由於我的英文能力不好,翻譯上若有謬誤的地方,還請多多指教。

How to use the Singleton design pattern

作者:Karl

出處:How to use the Singleton design pattern

翻譯:阿育

單例模式(Singleton Pattern)是四人幫(GoF,Gang of Four)設計模式之一。這個模式提供了一個將物件實例(instances)限制為單一實例的方法。若你過去曾使用過陌生的語法,這是一個很容易掌握的設計模式。

思考一下以下的類別(Class):

class Database
{
    public function __construct() { ... }
    public function connect() { ... }
    public function query() { ... }
    ...
}

每當我們需要一個連線時,這個類別建立了一個資料庫連線的類別實例,例如:

$pDatabase = new Database();
$aResult = $pDatabase->query('...');

假設我們在一個腳本的生命週使用上面的方法許多次,每當我們建立一個實例,也建立了一個新的資料庫物件(我們還建立了一個新的資料庫連線,但是以這個例子來說,這是沒必要的),同時也將耗費更多記憶體。

有時您可能想刻意建立多個類別實例,但在這裡我們不這麼做。

單例模式提供的方法便是去解決這個常見的問題。為了讓資料庫類別單一實例化,我們首先需要為這個類別添加一個新的屬性,我們將其命名為$m_pInstance:

class Database
{
    // Store the single instance of Database
    private static $m_pInstance;

    ...
}

此屬性將被用來存儲資料庫類別的單一實例。需注意,這個屬性必須是靜態(static)的。

接下來,我們需要將構造函數(constructor或稱建構函數、建構子)的存取範圍改為私有(private)。這是經常混淆視聽的陌生語法。

class Database
{
    // Store the single instance of Database
    private static $m_pInstance;

    private function __construct() { ... }
}

透過使用私有的構造函數,我們已經禁止了外部將類別實例化。因此如下面的程式碼將不可以被執行於類別之外。

$pDatabase = new Database();

為了建立單例模式,我們現在需要增加一個方法。增加下面的方法到資料庫類別中:

public static function getInstance()
{
    if (!self::$m_pInstance)
    {
        self::$m_pInstance = new Database();
    }

    return self::$m_pInstance;
}

這個看起來有趣的方法,它的責任是處理物件類別實例。請核對我們的靜態屬性$ m_pInstance,相對於此基本上這就容易理解了,如果建立資料庫物件透過呼叫建構函數,這是不合法的。請記住,我們已經讓__construct()方法成為私有的,所以物件實例的建立只能透過物件的方法。

這個方法函數最終將傳回一個靜態屬性的參照(reference)。在隨後呼叫了getInstance()將會回傳一個有效的$ m_pInstance參照,不會有新的物件實例被建立。

所以,我們的資料庫類別看起來差不多像這樣:

class Database
{
    // Store the single instance of Database
    private static $m_pInstance;

    private function __construct() { ... }

    public static function getInstance()
    {
        if (!self::$m_pInstance)
        {
            self::$m_pInstance = new Database();
        }

        return self::$m_pInstance;
    }
}

現在你可以在專案中的任何地方使用資料庫類別實例(不使用全域變數或函數的參數)。

(譯按:當然,你必須Include這個class啦 XD)

下面是範例與比較:

我們通常使用這種的方式建立物件:

$pDatabase = new Database();
$aResult = $pDatabase->query('...');

這則是單例模式所使用的方式:

$pDatabase = Database::getInstance();
$aResult = $pDatabase->query('...');

結論,單例模式是一種易於使用的設計模式,它限制了類別實例的數量。

範例檔詳見原文的附加檔案。

翻譯後記

如同作者所提,單例設計模式是一種很容易理解且容易使用的一種設計模式,目的在於確保一個類別只有一個實例,並提供對該實例的全域存取。。

Tagged : , ,

你可能會感興趣

留下迴響