前言
繼續上次的工廠模式, 接下來要整理的是裝飾器模式, 廢話不多說.
遇到的問題
當我們有一個遠古的類, 或者複雜的類, 又或者我們在這個類上需要作出一點修改, 這個時候如果 繼承不太合適, 當然不合適的原因可能很多, 比如 這個類繼承出來的子類沒有語義環境. 又或者繼承子類容易髒代碼. 這個時候我們需要一個簡單的辦法能夠修改原來的類, 但又不能違背開閉的原則.
代碼示例
如果需要裝飾的是類的抽象, 需要多實現一個接口.
// 類抽象
interface Phone
{
public function call(): void;
}
// 源類
class Iphone impletements Phone
{
public function call(): void
{
echo "call";
}
}
// 裝飾類
class IphoneDecorator impletements Phone
{
private Phone $phone;
public function __contruct(Phone $phone)
{
$this->phone = $phone;
}
public function call(): void
{
// call 需要做的新事情 僞代碼
echo "before call";
$this->phone->call();
echo "end call";
}
}
// 使用裝飾器
(new IphoneDecorator(new Iphone()))->call();
如果裝飾器實現多態, 那麼裝飾器本身也需要抽象, 如下:
// 類抽象
interface Phone
{
public function call(): void;
}
// 源類
class Iphone impletements Phone
{
public function call(): void
{
echo "call";
}
}
// 裝飾類抽象
interface IphoneDecorator extends Phone
{
}
// 裝飾類
class IphoneCallUserDecorator impletements IphoneDecorator
{
private Phone $phone;
public function __contruct(Phone $phone)
{
$this->phone = $phone;
}
public function call(): void
{
// call 需要做的新事情 僞代碼
echo "call user";
$this->phone->call();
}
}
// 裝飾類
class IphoneCallAdminDecorator impletements IphoneDecorator
{
private Phone $phone;
public function __contruct(Phone $phone)
{
$this->phone = $phone;
}
public function call(): void
{
// call 需要做的新事情 僞代碼
echo "call admin";
$this->phone->call();
}
}
// 此時可以動態選擇裝飾器
(new IphoneCallAdminDecorator(new Iphone()))->call();
(new IphoneCallUserDecorator(new Iphone()))->call();
如果需要裝飾的是類本身, 並且不需要實現多態裝飾可以簡化, 如下:
// 源類
class Iphone
{
public function call(): void
{
echo "call";
}
}
// 裝飾類
class IphoneDecorator
{
private Iphone $phone;
public function __contruct(Iphone $phone)
{
$this->phone = $phone;
}
public function call(): void
{
// call 需要做的新事情 僞代碼
echo "before call";
$this->phone->call();
echo "end call";
}
}
// 使用裝飾器
(new IphoneDecorator(new Iphone()))->call();