單例模式首先要知足三個條件:1.擁有一個構造函數,而且爲private 2.擁有一個靜態成員變量用來保持類的實例 3.擁有一個訪問這個實例的靜態方法。
單例模式一個類只有一個實例,並提供一個訪問它的全局訪問入口。單例模式是在你想控制實例數目,節省系統資源的時候使用。例如如下場景中:
一、一個黨只能有一個書記。 二、Windows 是多進程多線程的,在操做一個文件的時候,就不可避免地出現多個進程或線程同時操做一個文件的現象,因此全部文件的處理必須經過惟一的實例來進行。 三、一些設備管理器經常設計爲單例模式,好比一個電腦有兩臺打印機,在輸出的時候就要處理不能兩臺打印機打印同一個文件。
優勢: 一、在內存裏只有一個實例,減小了內存的開銷,尤爲是頻繁的建立和銷燬實例(好比管理學院首頁頁面緩存)。 二、避免對資源的多重佔用(好比寫文件操做)。
咱們在extend目錄下建立一個Single.php文件,如下是Single的內容。
咱們在index.php中建立一個getSingle方法
這時咱們發現,不管咱們調用多少次Single,new只執行一次。當$instance不存在的時候,就會new一個實例,當存在的時候就直接返回,最多執行一次new。
tp5框架用的單例模式在Container.php中,在thinkphp\library\think目錄下。
php
註冊樹模式經過將對象實例註冊到一顆全局的對象樹上,須要的時候從對象樹上採摘下來使用。
單例模式解決的是如何在整個項目中建立惟一對象實例的問題,工廠模式解決的是如何不經過new創建實例對象的方法。 那麼註冊樹模式想解決什麼問題呢? 在考慮這個問題前,咱們仍是有必要考慮下前兩種模式目前面臨的侷限。 首先,單例模式建立惟一對象的過程自己還有一種判斷,即判斷對象是否存在。存在則返回對象,不存在則建立對象並返回。 每次建立實例對象都要存在這麼一層判斷。 工廠模式更多考慮的是擴展維護的問題。 總的來講,單例模式和工廠模式能夠產生更加合理的對象。怎麼方便調用這些對象呢?並且在項目內如此創建的對象好像散兵遊勇同樣,不便統籌管理安排啊。因 而,註冊樹模式應運而生。無論你是經過單例模式仍是工廠模式仍是兩者結合生成的對象,都通通給我「插到」註冊樹上。我用某個對象的時候,直接從註冊樹上取 一下就好。這和咱們使用全局變量同樣的方便實用。 並且註冊樹模式還爲其餘模式提供了一種很是好的想法。
接下來咱們進行註冊樹模式的實戰講解,首先咱們在extend目錄下建立一個TestRegister.php文件。在這個類裏面咱們須要建立個註冊樹池子,而後建立幾個方法,set()方法是把咱們的參數掛載在池子裏,有兩個參數,一個是$key,一個是$object。set方法的邏輯就是把$object填充到$objects[$key]中去。
thinkphp
get方法須要傳入一個$key參數,咱們須要判斷$objects[$key]中是否存在,若是不存在,就填入;若是存在就返回。
設計模式
_unset方法一樣傳入$key參數,而後把$objects[$key]清空。
這就是一個簡單的註冊樹模式的代碼。完整代碼是這樣的:
而後咱們進行應用層邏輯編寫,一樣在extend目錄下建立一個A類,隨便輸出點內容。
而後咱們在index.php裏面建立一個方法,實例化A類,把A類掛在註冊池裏面。
緩存
若是咱們有多個相似於A的類,咱們就能夠經過上面register方法同樣去把它們掛在鏈接池裏面。php框架
依賴注入主要用來減小代碼間的耦合 有效分離對象和它所需的外部資源,接下來咱們經過代碼來對它進行理解。
首先咱們在extend目錄下建立一個di目錄,di目錄裏建立一個Person類,而後建立一個buy方法。接着再建立一個Car類,在裏面建立一個pay方法,而後返回價格。在buy方法裏面調用Car類裏面的pay方法。
而後咱們在入口文件裏面建立一個方法,而後調用Person類的buy方法。
這樣就能夠把Car類裏面的pay方法調用了。這就是一個簡單的依賴注入例子了。
其中Person類依賴於Car類,而後Car類注入到Person類中,由於person去買東西,不必定要買Car,還有其餘物品,這時就要把買的物品注入到Person類中去。這個時候問題來了,若是咱們buy的東西是其餘物品,而不是Car,那咱們就要對代碼進行修改了。修改以下:
首先把Person類裏面的buy方法修改,以前咱們寫的是指定的Car,這個時候咱們就要把指定的Car換成須要購買的物品,代碼以下,直接傳入對象,而後經過傳入的對象進行調用。
在入口文件的方法中,咱們直接建立一個須要用到的實例,而後傳給Person的方法。
這裏我new了一個Car類,若是咱們須要的不是Car類,而是其餘的類,那咱們就把Car換成須要的類。多線程
反射機制是在php5.0以後的版本增長的一個特性,這個特性給咱們提供了一個強大的API,容許咱們在php運行環境中去訪問和使用類、方法、屬性、參數和註釋,它的功能是很是強大的,常常用於高擴展的php框架,自動加載插件、生成文檔。好比說咱們進行生成php裏面的註釋等,就是經過php裏的反射機制進行的,甚至能夠用來擴展php語言。反射機制裏面有許多方法,咱們能夠根據文檔去查看各類方法的用途,文檔連接:php反射機制連接。在咱們使用反射機制的時候,首先要對類進行實例化,而後實例化類的反射機制,接下來進行調用這些方法。
框架
接下來咱們對上面的知識進行綜合性的實踐,建立一個簡單的容器類。
咱們進行操做的文件有如下幾個文件,首先是容器類Container,而後是Person類和Car類,最後是應用層index.php入口文件。
首先是容器類Container代碼:函數
<?php namespace di; class Container { /* * 存放數據的容器 * */ public $instances = []; /* * 容器中的對象實例 * */ protected static $instance; private function __construct() { } /* * 獲取當前容器的實例(單例) * * */ public static function getInstance(){ if (is_null(static::$instance)){ static::$instance = new static; } return static::$instance; } public function set($key,$value){ $this->instances[$key] = $value; } /* * 獲取容器裏面的實例 會用到反射機制 * */ public function get($key){ if(!empty($this->instances[$key])) { $key = $this->instances[$key]; } $reflect = new ReflectionClass($key); //獲取類的構造函數 $c = $reflect->getConstructor(); if (!$c){ return new $key; } $params = $c->getParameters(); // dump($params);exit(); if (empty($params)){ return new $key; }else{ foreach ($params as $param){ $class = $param->getClass(); if (!$class){ }else{ $args[] = $this->get($class->name); } } } return $reflect->newInstanceArgs($args); } }
而後是Person代碼this
<?php namespace di; class Person { public function __construct(Car $obj,$a = 124) { $this->obj = $obj; $this->a = $a; } /* * 依賴:Person類依賴於Car * 注入 Car類注入到Person * */ public function buy(){ return $this->a . "|" . $this->obj->pay(); } }
Car代碼spa
<?php namespace di; class Car { public function pay(){ return 123; } }
而後是index入口文件的方法代碼:
public function buy(){ Container::getInstance()->set("person","diPerson"); Container::getInstance()->set("car","diCar"); $obj = Container::getInstance()->get("person"); dump($obj->buy()); }
其中Person、Car、Container都在extend目錄下的di目錄中。
以上就是容器類的簡單實現。