你知道Laravel 用到了哪些設計模式 ?都是如何用的

Laravel00發表於2021-04-10

文章來自微信公眾號:PHP自學中心
學習與交流:Laravel技術交流微信群
本文給大家介紹了Laravel 中一些常用的設計模式,你一直都在用,可能你都不知道。。。


1:工廠模式

例如:Auth::user()

此處Auth這個類就是工廠中的方法,Auth是註冊樹中的別名。

好處:

類似於函式的封裝,使物件有一個統一的生成(例項化)入口。當我們物件所對應的類的類名發生變化的時候,我們只需要改一下工廠類類裡面的例項化方法即可。


2:單例模式

好處:

物件不可外部例項化並且只能例項化一次,節省資源。

實現方式:

private static $ins = null;                                                //設定私有的屬性

private function __construct() {}                                       //使外部無法new這個類

public static function getIns() {                                        //暴露給外部的呼叫方法

        if(self::$ins instanceof self) {

                return self::$ins;

        } else {

                self::$ins = new self();

                return self::$ins;

        }

}

宣告一個類的私有或者保護的靜態變數,構造方法宣告為私有(不允許外部進行new操作),如果不存在則例項化它,然後返回,如果存在則直接返回。


3:註冊樹模式

使用:

config/app裡的aliases陣列便是一個註冊樹

好處:

註冊樹模式就是使用陣列結構來存取物件,工廠方法只需要呼叫一次(可以放到系統環境初始化這樣的地方),以後需要呼叫該物件的時候直接從註冊樹上面取出來即可,不需要再呼叫工廠方法和單例模式。

實現方法:

class Register {

        protected static $objects

        function set($alias,$object) {                            //將物件對映到全域性樹上

                self::$objects[$alias]=$object;

        }

        static function get($name) {                             //獲取物件

                return self::$objects[$name];

        }

        function _unset($alias) {                                  //從全域性樹移除物件

                unset(self::$onjects[$alias]);

        }

}

$alias表示別名,自己設定

在工廠模式中新增

Register::set(‘db1’,$db);

其他任何地方呼叫只需要呼叫註冊器讀取即可

Register::$objects[‘db1’];


4:介面卡模式

將不同工具的不同函式介面封裝成統一的API,方便呼叫。如:mysqlmysqliPDO

實現:在介面類裡面申明統一的方法體,再讓不同的類去實現這個介面,和重寫其抽象方法。

interface Database {                                                  

        function connect($host,$user,$password,$dbname);

        function query($sql);

        function close();

}

然後再去用不同的工具函式去實現相同的介面。


5:策略模式

好處:

將一組特定的行為和演算法封裝成類,以適應某些特定的上下文環境,將邏輯判斷和具體實現分離,實現了硬編碼到解耦,並可實現IOC、依賴倒置、反轉控制。

實現:

1.定義一個策略介面檔案(UserStrategy.php),定義策略介面,宣告策略

2.定義具體類(FemaleUserStrategy.phpMaleUserStrategy.php),實現策略介面,重寫策略方法

class Page {

        protected $strategy;

        function index() {

                if($request->get('female')) {

                        $strategy=new FemaleUserStrategy();

                } else {

                        $strategy=new MaleUserStrategy();

                }

                $this->strategy->method();

        }

        public function __construct(UserStrategy $strategy) {

                $this->strategy=$strategy;

        }

}


6:資料物件對映模式

好處:將物件和資料儲存對映起來,對一個物件的操作會對映為對資料儲存的操作,這也是ORM的實現機制。

class Model {

        public $id;

        public $name;

        public $email;

        ……

        function __construct($id) {

               //建構函式,呼叫class時自動執行,用來初始化。

               //查詢邏輯

        }

        function __destruct() {

               //解構函式,當class呼叫完成後自動執行,用它來銷燬例項,釋放資源。

               //增刪改邏輯

        }

}


7:觀察者模式
使用:
觸發類Event

<?php

namespace App\Events;

abstract class Event
{
    //邏輯程式碼
}

監聽類EventListener

<?php

namespace App\Listeners;

use App\Events\SomeEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class EventListener
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  SomeEvent  $event
     * @return void
     */
    public function handle(SomeEvent $event)
    {
        //
    }
}

好處:

當一個物件狀態發生改變時,依賴它的物件全部會收到通知並自動更新,實現低耦合,非侵入式的通知與更新機制。


8:原型模式
與工廠模式類似,用於建立物件,不同在於:原型模式是先建立好一個原型物件,再通過clone原型物件來建立新的物件,原型模式適用於大物件的建立,僅需要記憶體拷貝即可。

$Object = new Object();
$object_1 = clone $Object;
$object_2 = clone $Object;


9:裝飾器模式
若要修改或新增一個類的功能,傳統的方式是寫一個子類繼承它,並重新實現類的方法。裝飾器模式僅需在執行時新增一個裝飾器物件即可動態的新增或修改類的功能。

傳統方法:

class Method2 extends Method {

        function doSomething() {

                echo "<div style='color:red'>"

                parent::doSomething();

                echo "</div>";

        }

}

interfa Decorator {                                             //定義裝飾器介面

        function beforeAction();

        function afterAction();

        //more decoratorMethod……

}

class SomeClass {

        protected $decorators = [];

        function addDecorator(Decorator $decorator) {

                $this->decorators[] = $decorator;

        }

        function beforeMethod() {

                foreach ($this->decorators as $row) {

                        $row->beforeAction();

                }

        }

        function afterMethod() {

                $decorators = array_reverse($this->decorators);     //做一個反轉

                foreach ($this->decorators as $row) {

                        $row->afterAction();

                }

        }

        function action() {

                $this->beforeMethod();

                //method;

                $this->afterMethod();

        }

}

class OneDecorator implements Decorator {

        protected $datas;

        function __construct($datas = 'request') {

                 $this->datas = $datas;

        }

        function beforeAction() {

                  echo "<div style='color:{$this->datas};'>";

        }

        function afterAction() {

                  echo "</div>";

        }

}

$Object = new \SomeClass();

$Object->addDecorator(new \OneDecorator('blue'));

//Add other decorator...

$Object->action();


10:迭代器模式

在不需要了解內部實現的前提下,遍歷一個聚合物件的內部元素,相對於傳統程式設計方式它可以遍歷元素所需的操作。

例如:

Object::all()

Iterator extends Traversable {                       //PHP內建迭代器介面

/* 方法 */

        abstract public mixed current (void)

        abstract public scalar key (void)

        abstract public void next (void)

        abstract public void rewind (void)

        abstract public boolean valid (void)

}

class ObjectAll implements \Iterator {

        protected $ids;                      //所有物件的id

        protected $index;                  //迭代器的當前位置

        protected $data = array();     //儲存從資料庫取到的所有物件

        function __construct() {

        //取出所有的id,$ids

}

        function current() {

                //獲取當前的元素的資料,第三個呼叫

                $id = $this->ids[$this->index]['id'];

                return Object::find($id);

        }

        function next() {

                //獲取下一個元素,第四個呼叫

                $this->index ++;

         }

         function valid() {

                 //驗證當前元素是否還有下一個元素(查詢當前是否有資料),第二個呼叫

                 return $this->index < count($this->$ids);

         }

         function rewind() {

                 //當迭代器執行到末尾時,重置迭代器到整個集合的開頭,最先呼叫

                 $this->index = 0;

         }

         function key() {

                  //獲取當前的索引,最後呼叫

                  return $this->index;

         }

}

$objects = new \ObjectAll();

foreach ($objects as $row) {

        dump($row->field);

        //增刪改查操作

}


11:代理模式
在客戶端與實體之間建立一個代理物件,客戶端對實體進行操作全部委派給代理物件,隱藏實體的具體實現細節(slave讀庫與master寫庫分離)。代理物件還可以與業務程式碼分離,部署到另外的伺服器,業務程式碼中通過PRC來委派任務。

interface DBproxy {
        function getInfo($id);
        function setInfo($id, $value);
}

class Proxy implements DBproxy {

        function get() {
                //DB::('slave');
                query

        }

        function set() {
                //DB::('master');
                query

        }

}

$proxy = new Proxy();
$proxy->get($id);
$proxy->set($id, $value);
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章