乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      PHP常用的三種設(shè)計(jì)模式

       yliu277 2019-07-09

      本文為大家介紹常用的三種php設(shè)計(jì)模式:單例模式、工廠模式、觀察者模式,有需要的朋友可以參考下。

      一、首先來看,單例模式

      所謂單例模式,就是確保某個類只有一個實(shí)例,而且自行實(shí)例化并向整個系統(tǒng)提供這個實(shí)例,即在應(yīng)用程序中只會有這個類的一個實(shí)例存在。
      通常單例模式用在僅允許數(shù)據(jù)庫訪問對象的實(shí)例中,從而防止打開多個數(shù)據(jù)庫連接,單例模式是一種常見的設(shè)計(jì)模式,在計(jì)算機(jī)系統(tǒng)中,線程池、緩存、日志對象、對話框、打印機(jī)、數(shù)據(jù)庫操作、顯卡的驅(qū)動程序常被設(shè)計(jì)成單例。

      一個單例類應(yīng)包括以下幾點(diǎn):
      和普通類不同,單例類不能被直接實(shí)例化,只能是由自身實(shí)例化。因此,要獲得這樣的限制效果,構(gòu)造函數(shù)必須標(biāo)記為private。
      要讓單例類不被直接實(shí)例化而能起到作用,就必須為其提供這樣的一個實(shí)例。因此,就必須要讓單例類擁有一個能保存類的實(shí)例的私有靜態(tài)成員變量和對應(yīng)的一個能訪問到實(shí)例的公共靜態(tài)方法。
      在PHP中,為防止對單例類對象的克隆來打破單例類的上述實(shí)現(xiàn)形式,通常還為基提供一個空的私有__clone()方法。好吧,廢話不多說,概括如下

      單例模式有以下3個特點(diǎn):

      1.只能有一個實(shí)例,必須擁有一個構(gòu)造函數(shù),并且必須被標(biāo)記為private

      2.必須自行創(chuàng)建這個實(shí)例,擁有一個保存類的實(shí)例的靜態(tài)成員變量

      3.必須給其他對象提供這一實(shí)例,擁有一個訪問這個實(shí)例的公共的靜態(tài)方法

      單例類不能再其它類中直接實(shí)例化,只能被其自身實(shí)例化。它不會創(chuàng)建實(shí)例副本,而是會向單例類內(nèi)部存儲的實(shí)例返回一個引用

      那么為什么要使用PHP單例模式?

      PHP一個主要應(yīng)用場合就是應(yīng)用程序與數(shù)據(jù)庫打交道的場景,在一個應(yīng)用中會存在大量的數(shù)據(jù)庫操作,針對數(shù)據(jù)庫句柄連接數(shù)據(jù)庫的行為,使用單例模式可以避免大量的new操作。因?yàn)槊恳淮蝞ew操作都會消耗系統(tǒng)和內(nèi)存的資源。

      在以往的項(xiàng)目開發(fā)中,沒使用單例模式前的情況如下:

      復(fù)制代碼
      復(fù)制代碼
      //初始化一個數(shù)據(jù)庫句柄 $db = new DB(...); //比如有個應(yīng)用場景是添加一條評論信息 $db->addComment(); ...... //如果我們要在另一地方使用這個評論信息,這時(shí)要用到數(shù)據(jù)庫句柄資源,可能會這么做 ...... function comment() {    $db = new DB(...);    $db->getCommentInfo(); ...... //可能有些朋友也許會說,可以直接使用global關(guān)鍵字!    global $db; ......
      復(fù)制代碼
      復(fù)制代碼

      的確global可以解決問題,也起到單例模式的作用,但在OOP中,我們建議拒絕這種編碼。因?yàn)間lobal存在安全隱患(全局變量不受保護(hù)的本質(zhì))。

      全局變量是面向?qū)ο蟪绦騿T遇到的引發(fā)BUG的主要原因之一。這是因?yàn)槿肿兞繉㈩惱売谔囟ǖ沫h(huán)境,破壞了封裝。如果新的應(yīng)用程序無法保證一開始就定義了相同的全局變量,那么一個依賴于全局變量的類就無法從一個應(yīng)用程序中提取出來并應(yīng)用到新應(yīng)用程序中。

      確切的講,單例模式恰恰是對全局變量的一種改進(jìn),避免那些存儲唯一實(shí)例的全局變量污染命名空間。你無法用錯誤類型的數(shù)據(jù)覆寫一個單例。這種保護(hù)在不支持命名空間的PHP版本里尤其重要。因?yàn)樵赑HP中命名沖突會在編譯時(shí)被捕獲,并使腳本停止運(yùn)行。

      我們用單例模式改進(jìn)下示例:

      復(fù)制代碼
      復(fù)制代碼
      class Single {
          private $name;//聲明一個私有的實(shí)例變量
          private function __construct(){//聲明私有構(gòu)造方法為了防止外部代碼使用new來創(chuàng)建對象。
          
          }
      
          static public $instance;//聲明一個靜態(tài)變量(保存在類中唯一的一個實(shí)例)
          static public function getinstance(){//聲明一個getinstance()靜態(tài)方法,用于檢測是否有實(shí)例對象
              if(!self::$instance) self::$instance = new self();
              return self::$instance;
          }
      
          public function setname($n){ $this->name = $n; }
          public function getname(){ return $this->name; }
      }
      
      $oa = Single::getinstance();
      $ob = Single::getinstance();
      $oa->setname('hello php world');
      $ob->setname('good morning php');
      echo $oa->getname();//good morning php
      echo $ob->getname();//good morning php
      復(fù)制代碼
      復(fù)制代碼

      單例模式的優(yōu)缺點(diǎn):

      優(yōu)點(diǎn):

      1. 改進(jìn)系統(tǒng)的設(shè)計(jì)

      2. 是對全局變量的一種改進(jìn)

      缺點(diǎn):

      1. 難于調(diào)試

      2. 隱藏的依賴關(guān)系

      3. 無法用錯誤類型的數(shù)據(jù)覆寫一個單例

      二、工廠模式

       工廠模式就是一種類,是指包含一個專門用來創(chuàng)建其他對象的方法的類,工廠類在多態(tài)性編程實(shí)踐中是至關(guān)重要的,它允許動態(tài)的替換類,修改配置,通常會使應(yīng)用程序更加靈活,熟練掌握工廠模式高級PHP開發(fā)人員是很重要的。

       工廠模式通常用來返回符合類似接口的不同的類,工廠的一種常見用法就是創(chuàng)建多態(tài)的提供者,從而允許我們基于應(yīng)用程序邏輯或者配置設(shè)置來決定應(yīng)實(shí)例化哪一個類,例如,可以使用這樣的提供者來擴(kuò)展一個類,而不需要重構(gòu)應(yīng)用程序的其他部分,從而使用新的擴(kuò)展后的名稱 。

      通常,工廠模式有一個關(guān)鍵的構(gòu)造,根據(jù)一般原則命名為Factory的靜態(tài)方法,然而這只是一種原則,工廠方法可以任意命名,這個靜態(tài)還可以接受任意數(shù)據(jù)的參數(shù),必須返回一個對象。

      具有為您創(chuàng)建對象的某些方法,這樣就可以使用工廠類創(chuàng)建對象,工廠模式在于可以根據(jù)輸入?yún)?shù)或者應(yīng)用程序配置的不同來創(chuàng)建一種專門用來實(shí)現(xiàn)化并返回其它類的實(shí)例的類,而不直接使用new,這樣如果想更改創(chuàng)建的對象類型,只需更改該工廠即可,

      先舉個示例吧:

      復(fù)制代碼
      復(fù)制代碼
      <?php class Factory {//創(chuàng)建一個基本的工廠類 static public function fac($id){//創(chuàng)建一個返回對象實(shí)例的靜態(tài)方法 if(1 == $id) return new A(); elseif(2==$id) return new B(); elseif(3==$id) return new C(); return new D(); } } interface FetchName {//創(chuàng)建一個接口 public function getname();// } class A implements FetchName{ private $name = 'AAAAA'; public function getname(){ return $this->name; } } class C implements FetchName{ private $name = 'CCCCC'; public function getname(){ return $this->name; } } class B implements FetchName{ private $name = 'BBBBB'; public function getname(){ return $this->name; } } class D implements FetchName{ private $name = 'DDDDD'; public function getname(){ return $this->name; } } $o = Factory::fac(6);//調(diào)用工廠類中的方法 if($o instanceof FetchName){ echo $o->getname();//DDDDD } $p=Factory::fac(3); echo $p->getname();//CCCCC ?>
      復(fù)制代碼
      復(fù)制代碼

      個人意見,再說簡單點(diǎn)吧,PHP工廠模式就是用一個工廠方法來替換掉直接new對象的操作,就是為方便擴(kuò)展,方便使用,在新增實(shí)現(xiàn)基類中的類中方法時(shí)候,那么在工廠類中無需修改,傳入?yún)?shù)可以直接使用,具體就是跳過工廠類修改,直接使用工廠類輸出想要的結(jié)果。在傳統(tǒng)習(xí)慣中,如果要生成一個類的話,在代碼中直接new一個對象,比如:

      class Database{
          
      }
       
      $db = new Database();

      下面介紹工廠模式的操作方法:

      復(fù)制代碼
      復(fù)制代碼
      class Database{ } //創(chuàng)建一個工廠類 class Factory { //創(chuàng)建一個靜態(tài)方法 static function createDatabase(){ $db = new Database; return $db; } }
      復(fù)制代碼
      復(fù)制代碼

      那么,當(dāng)我們想創(chuàng)建一個數(shù)據(jù)庫類的話,就可以使用這樣的方法:

      <?php 
          $db = Factory::createDatabase();
      ?>

      簡單工廠模式比直接new一個對象的好處是,比如Database這個類在很多php文件中都有使用到,當(dāng)Database這個類發(fā)生了某些變更,比如修改了類名、或者一些參數(shù)發(fā)生了變化,那這時(shí)候如果你使用的是$db = new Database這種傳統(tǒng)方法生成對象,那么在所有包含這種生成對象的php文件代碼中都要進(jìn)行修改。而使用工廠模式,只要在工廠方法或類里面進(jìn)行修改即可。而且工廠模式是其他設(shè)計(jì)模式的基礎(chǔ)。
      對上面的簡單工廠模式再進(jìn)一步優(yōu)化,比如:

       利用工廠類生產(chǎn)對象:

      復(fù)制代碼
      復(fù)制代碼
      <?php class Example { // The parameterized factory method public static function factory($type) { if (include_once 'Drivers/' . $type . '.php') { $classname = 'Driver_' . $type; return new $classname; } else { throw new Exception('Driver not found'); } } } // Load a MySQL Driver $mysql = Example::factory('MySQL'); // Load an SQLite Driver $sqlite = Example::factory('SQLite'); ?>
      復(fù)制代碼
      復(fù)制代碼

      簡單工廠模式又稱靜態(tài)工廠方法模式。從命名上就可以看出這個模式一定很簡單。它存在的目的很簡單:定義一個用于創(chuàng)建對象的接口。
      要理解工廠模式這個概念,讓我們最好談一下許多開發(fā)人員從事大型系統(tǒng)的艱苦歷程。在更改一個代碼片段時(shí),就會發(fā)生問題,系統(tǒng)其他部分 —— 您曾認(rèn)為完全不相關(guān)的部分中也有可能出現(xiàn)級聯(lián)破壞。
      該問題在于緊密耦合 。系統(tǒng)某個部分中的函數(shù)和類嚴(yán)重依賴于系統(tǒng)的其他部分中函數(shù)和類的行為和結(jié)構(gòu)。您需要一組模式,使這些類能夠相互通信,但不希望將它們緊密綁定在一起,以避免出現(xiàn)聯(lián)鎖。
      在大型系統(tǒng)中,許多代碼依賴于少數(shù)幾個關(guān)鍵類。需要更改這些類時(shí),可能會出現(xiàn)困難。例如,假設(shè)您有一個從文件讀取的 User 類。您希望將其更改為從數(shù)據(jù)庫讀取的其他類,但是,所有的代碼都引用從文件讀取的原始類。這時(shí)候,使用工廠模式會很方便。

      看下實(shí)例:

      復(fù)制代碼
      復(fù)制代碼
      <?php
       
          interface IUser
          {
            function getName();
          }
       
          class User implements IUser
          {        
            public $id;
            public function __construct( $id ) { }
       
            public function getName()
            {
              return 'Fantasy';
            }
          }
      ?>
      復(fù)制代碼
      復(fù)制代碼

      傳統(tǒng)方法使用 User 類,一般都是這樣:

      復(fù)制代碼
      復(fù)制代碼
      <?php //在頁面1 $obj = new User(1); //在頁面2 $obj2 = new User(2); //在頁面3 $obj3 = new User(3); .... ?>
      復(fù)制代碼
      復(fù)制代碼

      這時(shí)候,由于新的需求,使得User類要新增個參數(shù)或者User類名稱發(fā)生變化,User 類代碼發(fā)生變動,即:

      復(fù)制代碼
      復(fù)制代碼
      <?php
      class User implements IUser
      {
        public $id,$pre;
        public function __construct( $id , $pre = '') {...}
       
        public function getName()
        {
          return $this->pre.'Fantasy';
        }
      }
      
      ?>
      復(fù)制代碼
      復(fù)制代碼

      接著,恐怖的事情發(fā)生了,假設(shè)之前有 100 個頁面引用了之前的 User 類,那么這 100 個頁面都要發(fā)生相應(yīng)的改動:

      復(fù)制代碼
      復(fù)制代碼
      //在頁面1 $obj = new User(1,'aaa'); //在頁面2 $obj = new User(2,'aaa'); //在頁面3 $obj = new User(3,'aaa'); ...
      復(fù)制代碼
      復(fù)制代碼

      本來是一個小小的改動,但因緊密耦合的原因使得改動大吐血。而使用工廠模式則可以避免發(fā)生這種情況:

      復(fù)制代碼
      復(fù)制代碼
      //User類為變動前
      class UserFactory
      {
        public static function Create( $id )
        {
          return new User( $id );
        }
      }
       
      //頁面1
      $uo1 = UserFactory::Create( 1 );
       
      //頁面2
      $uo12 = UserFactory::Create( 2 );
      ....
      復(fù)制代碼
      復(fù)制代碼

      這時(shí)候需求變動,User 類也發(fā)生變動:

      復(fù)制代碼
      復(fù)制代碼
      <?php class User implements IUser { public $id,$pre; public function __construct( $id , $pre = '') {...} public function getName() { return $this->pre.'Jack'; } } ?>
      復(fù)制代碼
      復(fù)制代碼

      但是,我們不再需要去改動這 100 個頁面,我們要改的僅僅是這個工廠類:

      復(fù)制代碼
      復(fù)制代碼
      //
      class UserFactory
      {
        public static function Create( $id,$pre = 'aaa' )
        {
          return new User( $id ,$pre);
        }
      }
      復(fù)制代碼
      復(fù)制代碼

      其他100個頁面不用做任何改動,這就是工廠設(shè)計(jì)模式帶來的好處??聪耈ML圖:

      工廠模式uml圖

      三、觀察者模式
      觀察者模式為您提供了避免組件之間緊密耦合的另一種方法。該模式非常簡單:觀察者模式是一種事件系統(tǒng),意味著這一模式允許某個類觀察另一個類的狀態(tài),當(dāng)被觀察的類狀態(tài)發(fā)生改變的時(shí)候,觀察類可以收到通知并且做出相應(yīng)的動作;

      現(xiàn)在有兩派,有的人建議使用設(shè)計(jì)模式,有的人不建議使用設(shè)計(jì)模式!
      這就好比寫文章一樣,有的人喜歡文章按照套路走,比如敘事性質(zhì)的文章,時(shí)間,地點(diǎn),人物,事件。而有的人喜歡寫雜文或者散文,有的人喜歡寫詩詞!
      現(xiàn)在寫代碼很多地方類似于寫文章,但是在有些地方比寫文章需要更多的技能!寫文章寫多了一般也能寫出優(yōu)秀的文章,而代碼也一樣,寫多了也能寫出很多有寫的代碼!
      很多時(shí)候,我看設(shè)計(jì)模式的時(shí)候,有些設(shè)計(jì)模式只是吻合我的代碼習(xí)慣。但是你硬去套它,那么反而適得其反。——很多時(shí)候是學(xué)會了招式,在應(yīng)用中不知不覺的使用上這些招式,才能掌握其道,但是也不要拘泥于招式,正所謂“無招勝有招”嗎?
      我學(xué)設(shè)計(jì)模式的初衷,就是知道有這么個玩意兒?腦子里有這么個印象,也不會生套它!如果設(shè)計(jì)模式不符合你的習(xí)慣對你閱讀代碼反而是不利的!
      觀察者模式定義對象的一對多依賴,這樣一來,當(dāng)一個對象改變狀態(tài)時(shí),它的所有依賴者都會收到通知并自動更新!
      設(shè)計(jì)原則 

      在觀察者模式中,會改變的是主題的狀態(tài)以及觀察者的數(shù)目。用這個模式,你可以改變依賴于主題狀態(tài)的對象,卻不必改變主題?!页龀绦蛑袝兓姆矫妫缓髮⑵浜凸潭ú蛔兊姆矫嫦喾蛛x!
      主題和觀察者都使用接口:觀察者利用主題的接口向主題注冊,而主題利用觀察者接口通知觀察者。這樣可以讓兩者之間運(yùn)作正常,又同時(shí)具有松耦合的優(yōu)點(diǎn)! ——針對接口編程,不針對實(shí)現(xiàn)編程!
      觀察者模式利用“組合”將許多觀察者組合進(jìn)主題中。對象(觀察者——主題)之間的這種關(guān)系不是通過繼承產(chǎn)生的,而是在運(yùn)行時(shí)利用組合的方式產(chǎn)生的。 ——多用組合,少用繼承!
      好了,不說太多廢話,直接上代碼:
      復(fù)制代碼
      復(fù)制代碼
      <?php /** * 觀察者模式 * @author: Fantasy * @date: 2017/02/17 */ class Paper{ /* 主題 */ private $_observers = array(); public function register($sub){ /* 注冊觀察者 */ $this->_observers[] = $sub; } public function trigger(){ /* 外部統(tǒng)一訪問 */ if(!empty($this->_observers)){ foreach($this->_observers as $observer){ $observer->update(); } } } } /** * 觀察者要實(shí)現(xiàn)的接口 */ interface Observerable{ public function update(); } class Subscriber implements Observerable{ public function update(){ echo 'Callback\n'; } } ?>
      復(fù)制代碼
      復(fù)制代碼

      下面是測試代碼:

      復(fù)制代碼
      復(fù)制代碼
      /*  測試    */
      $paper = new Paper();
      $paper->register(new Subscriber());
      //$paper->register(new Subscriber1());
      //$paper->register(new Subscriber2());
      $paper->trigger();
      復(fù)制代碼
      復(fù)制代碼
      總結(jié)
             當(dāng)新對象要填入的時(shí)候,只需要在主題(又叫可觀察者)中進(jìn)行注冊(注冊方式很多,你也可以在構(gòu)造的時(shí)候,或者框架訪問的接口中進(jìn)行注冊),然后實(shí)現(xiàn)代碼直接在新對象的接口中進(jìn)行。這降低了主題對象和觀察者對象的耦合度。
      好的設(shè)計(jì)模式不會直接進(jìn)入你的代碼中,而是進(jìn)入你的大腦中。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多