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