設計模式整理--裝飾器模式

前言


繼續上次的工廠模式, 接下來要整理的是裝飾器模式, 廢話不多說.

遇到的問題


當我們有一個遠古的類, 或者複雜的類, 又或者我們在這個類上需要作出一點修改, 這個時候如果 繼承不太合適, 當然不合適的原因可能很多, 比如 這個類繼承出來的子類沒有語義環境. 又或者繼承子類容易髒代碼. 這個時候我們需要一個簡單的辦法能夠修改原來的類, 但又不能違背開閉的原則.

代碼示例


如果需要裝飾的是類的抽象, 需要多實現一個接口.

// 類抽象
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();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章