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