摘要:把和拼接在一起的場所是,所以需要造一個類,在其內部實現對的操作中實現了把原有的進過個的裝飾后得到的新的,新的還是的實現,還是原來的物種。
說明:Laravel中Middleware的實現主要利用了Decorator Pattern的設計,本文主要先學習下Decorator Pattern如何實現,為后面學習Middleware的設計做個鋪墊。Decorator Pattern和Adapter Pattern會有很多相似之處,但相比較于Adapter Pattern重點突出adapter,Decorator Pattern重點突出的是wrapper,兩個不是同一概念。
開發環境:Laravel5.3 + PHP7 + OS X 10.11
Decorator PatternDecorator Pattern作為一種結構型模式,可以給現有對象Component裝飾decorate幾個feature,而不影響原有的Component對象,這幾個feature就是裝飾對象Decorator。這種設計很好用,因為可以隨時增加或減少想要的feature,并且增加或減少這種操作又很簡單,實現了程序松耦合。就像Laravel中每一個middleware就是一個feature,如果想要增加一個不緩存request的feature,可以增加一個middleware假設叫做NoCacheMiddleware,寫好后只需要在app/Http/Kernel.php文件中添加下配置就可??聪乱粋€簡單的demo實例,看看如何使用Decorator Pattern。
先定義一個IMiddleware的接口,保證設計的features都是同一物種,即只有實現了該接口的feature才稱為middleware:
namespace MyRightCapitalDevelopmentDecoratorPattern; interface IMiddleware { public function handle(); }
在該接口中定義一個handle()函數,每一個feature必須實現這個handle()來做邏輯?,F在需要設計5個features,并且每一個feature都必須是middleware:
$features = [ CheckForMaintenanceMode::class, AddQueuedCookiesToResponse::class, StartSession::class, ShareErrorsFromSession::class, VerifyCsrfToken::class, ];
OK,現在實現第一個feature,并改造為middleware:
namespace MyRightCapitalDevelopmentDecoratorPattern; class CheckForMaintenanceMode implements IMiddleware { /** * @var MyRightCapitalDevelopmentDecoratorPatternIMiddleware */ private $middleware; /** * CheckForMaintenanceMode constructor. * * @param MyRightCapitalDevelopmentDecoratorPatternIMiddleware $middleware */ public function __construct(IMiddleware $middleware) { $this->middleware = $middleware; } public function handle() { echo "Check if the application is in the maintenance status." . PHP_EOL; $this->middleware->handle(); } }
第一個middleware是CheckForMaintenanceMode,需要檢查程序是否處于維護模式。實現第二個feature,并改造為middleware:
namespace MyRightCapitalDevelopmentDecoratorPattern; class AddQueuedCookiesToResponse implements IMiddleware { /** * @var MyRightCapitalDevelopmentDecoratorPatternIMiddleware */ private $middleware; /** * AddQueuedCookiesToResponse constructor. * * @param MyRightCapitalDevelopmentDecoratorPatternIMiddleware $middleware */ public function __construct(IMiddleware $middleware) { $this->middleware = $middleware; } public function handle() { $this->middleware->handle(); echo "Add queued cookies to the response" . PHP_EOL; } }
第二個middleware實現把cookie添加到response。實現第三個feature,并改造為middleware:
namespace MyRightCapitalDevelopmentDecoratorPattern; class StartSession implements IMiddleware { /** * @var MyRightCapitalDevelopmentDecoratorPatternIMiddleware */ private $middleware; /** * StartSession constructor. * * @param MyRightCapitalDevelopmentDecoratorPatternIMiddleware $middleware */ public function __construct(IMiddleware $middleware) { $this->middleware = $middleware; } public function handle() { echo "Start session of this request." . PHP_EOL; $this->middleware->handle(); echo "Close session of this request." . PHP_EOL; } }
第三個feature主要實現開啟和關閉session。實現第四個feature,并改造為middleware:
class ShareErrorsFromSession implements IMiddleware { /** * @var MyRightCapitalDevelopmentDecoratorPatternIMiddleware */ private $middleware; /** * ShareErrorsFromSession constructor. * * @param MyRightCapitalDevelopmentDecoratorPatternIMiddleware $middleware */ public function __construct(IMiddleware $middleware) { $this->middleware = $middleware; } public function handle() { $this->middleware->handle(); echo "Share the errors variable from request to the views." . PHP_EOL; } }
第四個feature主要實現共享變量$errors,以便在視圖中使用該變量。實現第五個feature,并改造為middleware:
namespace MyRightCapitalDevelopmentDecoratorPattern; class VerifyCsrfToken implements IMiddleware { /** * @var MyRightCapitalDevelopmentDecoratorPatternIMiddleware */ private $middleware; /** * VerifyCsrfToken constructor. * * @param MyRightCapitalDevelopmentDecoratorPatternIMiddleware $middleware */ public function __construct(IMiddleware $middleware) { $this->middleware = $middleware; } public function handle() { echo "Verify csrf token when post request." . PHP_EOL; $this->middleware->handle(); } }
第五個feature主要實現CSRF驗證。OK,現在每一個feature都已經實現了,并將作為Decorator來裝飾初始的Component。
OK,Decorator Pattern中已經有了五個Decorators,現在需要實現一個Component,然后用這五個Decorators來裝飾Component。
現在定義一個Component接口,保證Component與Decorator是相似物種,并且Component又有自己的實現接口:
namespace MyRightCapitalDevelopmentDecoratorPattern; interface IComponent extends IMiddleware { public function getRequest(); }
現在構造一個Component:
namespace MyRightCapitalDevelopmentDecoratorPattern; class Request implements IComponent { public function handle() { echo "This is a request from the client. And this request will go through the middlewares." . PHP_EOL; } public function getRequest() { return $this; } }
OK,在Decorator Pattern中,目前已經構造好了Component和Decorator。把Component和Decorator拼接在一起的場所是Client,所以需要造一個Client類,在其內部實現對Component的Decorate操作:
namespace MyRightCapitalDevelopmentDecoratorPattern; class Client { /** * @var MyRightCapitalDevelopmentDecoratorPatternRequest */ protected $request; /** * @var MyRightCapitalDevelopmentDecoratorPatternIMiddleware */ protected $response; public function __construct() { // Component $this->request = new Request(); // Decorate the Component $this->response = $this->wrapDecorator($this->request); } /** * @param MyRightCapitalDevelopmentDecoratorPatternIMiddleware $decorator * * @return MyRightCapitalDevelopmentDecoratorPatternIMiddleware */ public function wrapDecorator(IMiddleware $decorator) { $decorator = new VerifyCsrfToken($decorator); $decorator = new ShareErrorsFromSession($decorator); $decorator = new StartSession($decorator); $decorator = new AddQueuedCookiesToResponse($decorator); $response = new CheckForMaintenanceMode($decorator); return $response; } /** * @return MyRightCapitalDevelopmentDecoratorPatternIMiddleware */ public function getResponse() { return $this->response->handle(); } }
Client中wrapDecorator()實現了把原有的Component進過5個Middlewares的裝飾后得到的新的Component,新的Component還是IMiddleware的實現,還是原來的物種。整個UML圖:
OK,現在執行整個Decorator Pattern,看看是不是這些middlewares已經被裝飾進原來的Component,創建一個index.php文件:
// 加載composer的autoload.php文件 include __DIR__ . "/../../../vendor/autoload.php"; $client = new MyRightCapitalDevelopmentDecoratorPatternClient(); $client->getResponse();
php index.php文件看看輸出什么:
Check if the application is in the maintenance status. Start session of this request. Verify csrf token when post request. This is a request from the client. And this request will go through the middlewares. Share the errors variable from request to the views. Close session of this request. Add queued cookies to the response.
的確,五個middlewares已經裝飾了原有的component,并檢查下裝飾次序是否是正確的?
實際上,Client中的$this->response等同于:
$response = new CheckForMaintenanceMode( new AddQueuedCookiesToResponse( new StartSession( new ShareErrorsFromSession( new VerifyCsrfToken( new Request() ) ) ) ) );
所以,執行次序是:
1. CheckForMaintenanceMode::handle() -> 先執行 echo "Check if the application is in the maintenance status.", 然后執行 AddQueuedCookiesToResponse::handle() 2. AddQueuedCookiesToResponse::handle() -> 先執行 StartSession::handle(), 然后執行 echo "Add queued cookies to the response." 3. StartSession::handle() -> 先執行 echo "Start session of this request.", 然后執行 ShareErrorsFromSession::handle(), 最后執行 echo "Close session of this request." 4. ShareErrorsFromSession::handle() -> 先執行VerifyCsrfToken::handle(), 然后執行 echo "Share the errors variable from request to the views." 5. VerifyCsrfToken::handle() -> 先執行 echo "Verify csrf token when post request.", 然后執行 Request::handle() 6. Request::handle() -> 執行 echo "This is a request from the client. And this request will go through the middlewares." // So,執行順序等同于: echo "Check if the application is in the maintenance status." -> echo "Start session of this request." -> echo "Verify csrf token when post request." -> echo "This is a request from the client. And this request will go through the middlewares." -> echo "Share the errors variable from request to the views." -> echo "Close session of this request." -> echo "Add queued cookies to the response." ->
在Laravel里每一個Middleware中有前置操作和后置操作。在本demo里echo語句前置于$this->middleware->handle();則為前置操作,后置則為后置操作。
OK,再加一個Kernel類,保證Request經過Middleware的前置操作后進入Kernel,然后從Kernel出來進入Middlewares的后置操作,一步步過濾:
namespace MyRightCapitalDevelopmentDecoratorPattern; interface IKernel extends IMiddleware { } class Kernel implements IKernel { public function handle() { echo "Kernel handle the request, and send the response." . PHP_EOL; } } // 修改Request class Request implements IRequest { /** * @var MyRightCapitalDevelopmentDecoratorPatternIKernel */ private $kernel; public function __construct(IKernel $kernel) { $this->kernel = $kernel; } public function handle() { echo "This request has been filtering by the before action in the middlewares, and go into the kernel." . PHP_EOL; $this->kernel->handle(); echo "The request has been handled by the kernel, and will be send to the after action in the middlewares" . PHP_EOL; } public function getRequest() { return $this; } } // 修改下Client的構造函數 public function __construct() { // Component $this->request = new Request(new Kernel()); // Decorate the Component $this->response = $this->wrapDecorator($this->request); }
則再次執行index.php文件,得到:
Check if the application is in the maintenance status. Start session of this request. Verify csrf token when post request. This request has been filtering by the before action in the middlewares, and go into the kernel. Kernel handle the request, and send the response. The request has been handled by the kernel, and will be send to the after action in the middlewares Share the errors variable from request to the views. Close session of this request. Add queued cookies to the response.
具體流程上文已經討論,可畫一張草圖展示處理流程,其中Before表示該Middleware的前置操作,After表示該Middleware的后置操作:
OK,使用Decorator Pattern來層層過濾Request,并實現分層,最后進入Kernel執行得到Response,然后Response經過層層過濾,返回給客戶端。非常贊的設計。
總結:本文主要學習Laravel如何使用Decorator Pattern來設計Middleware。下一篇學習下Laravel中Middleware的源碼。
歡迎關注Laravel-China。
RightCapital招聘Laravel DevOps
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30438.html
摘要:學習筆記之已經聊過使用了來設計,看源碼發現其巧妙用了和的一些數組函數來設計。開發環境內置函數和看源碼之前,先看下這幾個內置函數的使用。學習筆記之實例化源碼解析已經聊過的實例化,得到中的變量,即的實例化對象。后面再學習下的源碼,到時見。 說明:本文主要學習Laravel的Middleware的源碼設計思想,并將學習心得分享出來,希望對別人有所幫助。Laravel學習筆記之Decorato...
摘要:源碼解析這個類的源碼主要就是文件的操作和文件屬性的操作,而具體的操作是通過每一個實現的,看其構造函數看以上代碼知道對于操作,實際上是通過的實例來實現的。可以看下的使用上文已經說了,使得對各種的操作變得更方便了,不管是還是得。 說明:本文主要學習下LeagueFlysystem這個Filesystem Abstract Layer,學習下這個package的設計思想和編碼技巧,把自己的一...
摘要:裝飾對象包含一個真實對象的引用裝飾對象接受所有來自客戶端的請求。裝飾對象可以在轉發這些請求以前或以后增加一些附加功能。在面向對象的設計中,通常是通過繼承來實現對給定類的功能擴展。 Decorator Pattern 裝飾者模式 綱要: 1. 一個初學者的疑惑 2. 裝飾者模式的特點 3. 簡單case掌握裝飾者模式 4. laravel中裝飾者模式的應用 Con...
摘要:裝飾者模式是在開放關閉原則下實現動態添加或減少功能提高程序的擴展性詳細介紹注本文可以作為學習裝飾者模式的基礎篇但是我個人更建議配套裝飾者模式來學習效果更佳本文中的例子是由框架關鍵技術解析中摘抄的。 裝飾者模式:是在開放-關閉原則下實現動態添加或減少功能,提高程序的擴展性.詳細介紹注: 本文可以作為學習裝飾者模式的基礎篇,但是我個人更建議配套Decorator Pattern With...
摘要:使用了來表示該,該接口也是對的抽象,暴露了一些常用方法判斷是否滿足要求的方法的讀寫相關操作獲取元數據方法操作指針相關方法等等。本篇主要學習下相關使用。后續還會分享相關使用,到時見。 說明:本文主要學習guzzlehttp/guzzle package的使用,該package提供了一套發送HTTP請求API,就像phpunit package, mockery package, symf...
閱讀 2164·2021-11-11 16:55
閱讀 1685·2019-08-30 15:54
閱讀 2817·2019-08-30 15:53
閱讀 2211·2019-08-30 15:44
閱讀 1152·2019-08-30 15:43
閱讀 965·2019-08-30 11:22
閱讀 1942·2019-08-29 17:20
閱讀 1566·2019-08-29 16:56