PHP設計模式(一)—單例模式(Singleton Pattern)

ciscopuke發表於2021-09-09

單例模式(Singleton Pattern):顧名思義,就是隻有一個例項。作為物件的建立模式,單例模式確保某一個類只有一個例項,而且自行例項化並向整個系統提供這個例項。

(一)為什麼要使用PHP單例模式

1,php的應用主要在於資料庫應用, 一個應用中會存在大量的資料庫操作, 在使用物件導向的方式開發時, 如果使用單例模式,
則可以避免大量的new 操作消耗的資源,還可以減少資料庫連線這樣就不容易出現 too many connections情況。

2,如果系統中需要有一個類來全域性控制某些配置資訊, 那麼使用單例模式可以很方便的實現. 這個可以參看zend Framework的FrontController部分。

3,在一次頁面請求中, 便於進行除錯, 因為所有的程式碼(例如資料庫操作類db)都集中在一個類中, 我們可以在類中設定鉤子, 輸出日誌,從而避免到處var_dump, echo

(二)單例模式結構圖
圖片描述

(三)單例模式的實現

1,私有化一個屬性用於存放唯一的一個例項

2,私有化構造方法,私有化克隆方法,用來建立並只允許建立一個例項

3,公有化靜態方法,用於向系統提供這個例項

(四)程式碼實現

class Singleton{
        //存放例項
        private static $_instance = null;

        //私有化構造方法、
        private function __construct(){
            echo "單例模式的例項被構造了";
        }
        //私有化克隆方法
        private function __clone(){

        }

        //公有化獲取例項方法
        public static function getInstance(){
            if (!(self::$_instance instanceof Singleton)){
                self::$_instance = new Singleton();
            }
            return self::$_instance;
        }
    }

    $singleton=Singleton::getInstance();

優點:因為靜態方法可以在全域性範圍內被訪問,當我們需要一個單例模式的物件時,只需呼叫getInstance方法,獲取先前例項化的物件,無需重新例項化。

缺點:

(五)使用Trait關鍵字實現類似於繼承單例類的功能

Trait Singleton{
        //存放例項
        private static $_instance = null;
        //私有化克隆方法
        private function __clone(){

        }

        //公有化獲取例項方法
        public static function getInstance(){
            $class = __CLASS__;
            if (!(self::$_instance instanceof $class)){
                self::$_instance = new $class();
            }
            return self::$_instance;
        }
    }

class DB {
    private function __construct(){
        echo __CLASS__.PHP_EOL;
    }
}

class DBhandle extends DB {
    use Singleton;
    private function __construct(){
        echo "單例模式的例項被構造了";
    }
}
$handle=DBhandle::getInstance();

//注意若父類方法為public,則子類只能為pubic,若父類為private,子類為public ,protected,private都可以。

補充,大多數書籍介紹單例模式,都會講三私一公,公有化靜態方法作為提供物件的介面,私有屬性用於存放唯一一個單例物件。私有化構造方法,私有化克隆方法保證只存在一個單例。

但實際上,雖然我們無法透過new 關鍵字和clone出一個新的物件,但我們若想得到一個新物件。還是有辦法的,那就是透過序列化和反序列化得到一個物件。私有化sleep()和wakeup()方法依然無法阻止透過這種方法得到一個新物件。或許真得要阻止,你只能去__wakeup新增刪除一個例項的程式碼,保證反序列化增加一個物件,你就刪除一個。不過這樣貌似有點怪異。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4369/viewspace-2798479/,如需轉載,請註明出處,否則將追究法律責任。

相關文章