裝飾器模式以及Laravel框架下的中間件應用

  Laravel框架的中間件使用:從請求進來到響應返回,通過中間件的層層包裝,這種場景很適合用到一種設計模式---裝飾器模式。php

  裝飾器模式的做用,多種外界因素改變對象的行爲。使用繼承的方式改變行爲不太被建議。設計模式

  裝飾器模式,便是有多個要改變對象的東西(裝飾類),這些裝飾類均實現一個接口。每一個類在實現的接口中再調用構造器(或是setter等方法)傳過來的其餘裝飾類對象的實現。數組

  簡單用一段代碼描述下:  閉包

<?php

interface Decorate {
    function getInfo();
}

/**
 * Class DecoateA
 * 初始化一個裝飾對象
 */
class DecoateA implements Decorate{

    /**
     * 實現接口
     */
    public function getInfo() {
        echo __CLASS__;
    }
}

/**
 * Class DecoateB
 * 裝飾DecoateA 的裝飾類
 */
class DecoateB implements Decorate{

    /**
     * DecoateB constructor.
     * @param Decorate $dec
     * 構造器 傳過來其餘裝飾類
     */
    public function __construct(Decorate $dec) {
        $this->dec = $dec;
    }

    /**
     * 實現接口
     */
    public function getInfo() {
        echo __CLASS__;
        $this->dec->getInfo();
    }
}


$obj = new DecoateA();// 初始一個對象
$obj = new DecoateB($obj);// 裝飾對象

$obj->getInfo();// DecoateBDecoateA

以上代碼,能夠簡單理解裝飾器模式。框架

 

 

再說Laravel的裝飾器模式應用: (這裏用靜態方法模擬一下)函數

不像是上邊的例子,把裝飾類傳過去,Laravel用到了大量的閉包Closure代替this

一段代碼spa

<?php

interface Step
{
    public static function go(Closure $next);
}

/**
 * Class FirstStep
 * 裝飾一
 */
class FirstStep implements Step
{
    public static function go(Closure $next)
    {
        echo __CLASS__." start<br/>";
        $next();
        echo __CLASS__." end<br/>";
    }
}

/**
 * Class SecondStep
 * 裝飾二
 */
class SecondStep implements Step
{
    public static function go(Closure $next)
    {
        echo __CLASS__." start<br/>";
        $next();
        echo __CLASS__." end<br/>";
    }
}


function goFun($step, $className)
{
    return function () use ($step, $className)
    {
        return $className::go($step);
    };
}

function then()
{
    $step = ['FirstStep', 'SecondStep'];
    $prepare = function () {
        echo "_init_"."<br/>";
    };
    call_user_func(array_reduce($step, "goFun", $prepare));
}

then();

/**
SecondStep start
FirstStep start
_init_
FirstStep end
SecondStep end
**/

 

這裏須要理解下 array_reduct()的用法,第一個參數是被循環的數組,第二個是回調函數(其中回調函數的第一個參數是每次該函數上一次的return值,不然是array_reduce的第三個參數的初始值),第三個參數是初始值。設計

對於then() 的內部實現,可能開始理解比較困難。能夠分拆一下實現:以下代碼code

// 初始閉包
$initFun = function (){
    echo "_init_"."<br/>";
};

// 至關於array_reduce 第一次執行
$obj = function () use ($initFun) {
    return FirstStep::go($initFun);
};

// 至關於array_reduce 第二次執行。go傳遞的都是個閉包函數
SecondStep::go($obj);
相關文章
相關標籤/搜索