【面向對象的PHP】之模式:單例

單例模式

模式系列的開篇,首先介紹的是我最喜歡的單例模式(Singleton),簡單而言,這屬於:生成一個、且只生成一個對象實例的特殊類。segmentfault

這個惟一存在的類,將替代Global關鍵字,而且更安全。設計模式

產生前提

全局變量是OOP程序猿遇到的主要BUG源泉之一,全局變量的衝突也是極其危險的,由於PHP不會對其產生任何級別的錯誤,若是結果不能直接觀測,那麼你的程序可能會讓你感到懵圈。安全

儘管命名空間的出現,必定程度上的避免了全局衝突,然而,在空間內的衝突仍然可能存在。可全部的類均可以訪問它,全局變量還是巨大的誘惑。測試

問題

良好設計的系統:經過方法調用傳遞對象實例。this

每一個類都會與背景環境保持獨立,並經過清晰的通訊方式,與系統中其它部分進行無耦合協做。spa

但有時,你不得不經過 中間件 來溝通各個組件,中間件會致使依賴、耦合,而且,假若組件返回的參數之一,包含了這個中間件,將會致使「依賴污染」。設計

怎樣的中間件才能避免上述狀況呢?調試

  1. 如同Global,它能夠被全部對象使用;code

  2. 不存儲在全局變量中,不接受覆寫;面向對象設計模式

  3. 它在整個系統中,是惟一的。

實現

爲了解決這個問題,咱們能夠強行控制「對象實例化」,咱們經過簡單地定義一個私有構造方法,建立一個沒法從外部實例化的類,經過靜態方法與靜態屬性,來間接實例化它:

class Preferences {
    private $props = array();
    private static $instance;
    
    private function __construct() { }
    
    public static function getInstance() {
        if (empty(self::$instance)) {
        self::$instance = new Preferences();
        }
        
        return self::$instance;
    }
    
    public function setProperty($key, $val) {
        $this->props[$key] = $val;
    }
    
    public function getProperty($key) {
        return $this->props[$key];
    }
}

單例類建立完畢後,咱們進行測試:

// 設置屬性
$pref = Preferences::getInstance();
$pref->setProperty("name", "UiTest");

unset($pref);

// 調用屬性
$pref2 = Preferences::getInstance();
echo $pref2->getProperty("name");

最終能夠獲得輸出:UiTest,而且,你能夠去設置任何值,來測試它的可用性。

最後附贈一張UML圖:

單例模式的UML

(感謝雲繪圖軟件:ProcessOn)

總結

Bad Result:單例與全局變量都會:建立難以調試的依賴關係、被誤用、繞過安全的通訊接口,因此,須要謹慎當心的部署單例類。
Nice Result:與全局變量不一樣,單例的任何錯誤與衝突,都將以報錯的形式出現(除非你關閉了錯誤提示),這下,你就能夠放心的使用它了。

面向對象設計模式 - 目錄

相關文章
相關標籤/搜索