定義
動態地給一個物件增加一些額外的職責,就增加物件功能來說,裝飾模式比生成子類實現更為靈活。這樣可以給某個物件而不是整個類新增一些功能。
設計的原則和思想
- 解耦的是裝飾者和被裝飾者。
- 不變部分是被裝飾者,變化部分是裝飾者。
- 核心思想是對物件自身功能進行增強。
一句話概括設計模式
透過組合的方式,增強物件自身的功能,並且支援多個裝飾器巢狀使用。
經典裝飾者模式
結構中包含的角色
- Component(抽象構件)
- ConcreteComponent(具體構件)
- Decorator(抽象裝飾類)
- ConcreteDecorator(具體裝飾類)
最小可表達程式碼
abstract class Component
{
public abstract function display();
}
class ConcreteComponent extends Component
{
public function display()
{
echo ' 具體構件 ';
}
}
abstract class ComponentDecorator extends Component
{
protected $component;
public function __construct(Component $component)
{
$this->component = $component;
}
}
class ConcreteDecorator extends ComponentDecorator
{
public function display()
{
echo ' 裝飾前的行為 ';
$this->component->display();
echo ' 裝飾後的行為 ';
}
}
$decorator = new ConcreteDecorator(new ConcreteComponent);
$decorator->display();
Laravel管道閉包方式的裝飾者模式
結構中包含的角色
- MiddlewareManager (中介軟體管理類/修飾者管理類)
- Middleware (抽象中介軟體/抽象裝飾者)
- ConcreteMiddleWare (具體中介軟體/具體裝飾者)
- Controller (控制器/被裝飾者)
- Request (請求類)
最小可表達程式碼
class MiddlewareManager
{
protected $request;
protected $middlewares = [];
public function send($request)
{
$this->request = $request;
return $this;
}
public function through($middlewares)
{
$this->middlewares = is_array($middlewares) ? $middlewares : func_get_args();
return $this;
}
public function then(Closure $controllerClosure)
{
$middlewareClosure = array_reduce(
array_reverse($this->middlewares), $this->carry(), $this->prepareDestination($controllerClosure)
);
return $middlewareClosure($this->request);
}
protected function prepareDestination(Closure $controllerClosure)
{
return function ($request) use ($controllerClosure) {
return $controllerClosure($request);
};
}
protected function carry()
{
return function ($controllerClosure, $middleware) {
return function ($request) use ($controllerClosure, $middleware) {
return $middleware->handle($request, $controllerClosure);
};
};
}
}
class Request{}
interface Middleware
{
public function handle(Request $request, Closure $controllerClosure);
}
class ConcreteMiddleWare implements Middleware
{
public function handle(Request $request, Closure $controllerClosure)
{
var_dump("前");
$response = $controllerClosure($request);
var_dump("後");
return $response;
}
}
class Controller
{
public function test(Request $request)
{
var_dump("執行控制器的方法");
return ['status' => 200];
}
}
$response = (new MiddlewareManager)
->send(new Request)
->through([new ConcreteMiddleWare])
->then(function ($request) {
return (new Controller)->test($request);
});
var_dump($response);
優點
- 你可以在執行時新增或刪除物件的功能。
- 你可以用多個裝飾封裝物件來組合幾種行為。
- 裝飾類和被裝飾類可以獨立發展,不會相互耦合。
- 透過組合來替代繼承,使用物件之間的關聯關係取代類之間的繼承關係。
缺點
- 在封裝器棧中刪除指定裝飾器比較困難。
- 實現行為不受裝飾棧順序影響的裝飾比較困難。
- 比繼承更容易出錯,排錯也比較困難,程式碼較為繁瑣。
- 多層裝飾比較複雜。
何時使用
- 擴充套件一個類的功能。
- 動態增加功能。
- 當不能採用繼承的方式(final)對系統進行擴充套件或者採用繼承不利於系統擴充套件和維護(大量獨立擴充套件)
實際應用場景
- Laravel的中介軟體。
- 漢堡包,加番茄醬,加牛肉,加雞蛋。。。
- Java的IO流。
本作品採用《CC 協議》,轉載必須註明作者和本文連結