什么是装饰模式?
- 装饰模式是组合+委托的变种,也就是在组合模式的基础上,在装饰类的构造函数中,增加了对象委托。
应用场景
- 和组合模式一样,因为它的优雅和易理解,所以在很多场景下都适用。
注意事项
- 唯一需要注意的地方就是不要过度使用。
具体实现
- 和组合模式的不同点:组合在于局部对象和组合对象,装饰在于委托;组合在于对局部对象的组合,装饰在于对子类对象的委托。
- 实例场景:还是延续宝马老板的要求,要求财务出实时报表,查看各个工厂的收支、利润情况。
- 组合模式中,组合类对局部对象进行了统一 add 操作,并在组合类中计算所有局部对象的收支、利润情况。
- 按照装饰的定义,可以将各工厂的收支情况进行委托计算。
- UML图(各工厂委托对象给SettleDecorator抽象类,进行嵌套计算)
代码实例
Settle.php
<?php
namespace com\wdqz\decorate;
/**
* 装饰模式-结算接口
* - 宝马公司的需求是收支结算,这里结算工具将成为各分厂的基本单元
*
* @author woodhead
* @date 2023年11月25日23:53:19
*/
interface Settle
{
/**
* 收入
* @return mixed
*/
public function revenue();
/**
* 支出
* @return mixed
*/
public function expend();
}
SettleDecorator.php(装饰抽象类)
<?php
namespace com\wdqz\decorate;
/**
* 装饰类
* - 构造方法中,对Settle的实现类对象进行委托
*/
abstract class SettleDecorator implements Settle
{
/**
* @var ?Settle $settle 装饰对象
*/
protected ?Settle $settle = null;
/**
* 收入
*/
protected float $revenue = 0.00;
/**
* 支出
*/
protected float $expend = 0.00;
/**
* 构造函数
* @param Settle|null $settle
*/
public function __construct(?Settle $settle)
{
$this->settle = $settle;
}
/**
* 结果
* @return array
*/
public function result(): array
{
if (empty($this->settle)) {
return [];
}
$profit = $this->revenue - $this->expend;
return [$this->revenue, $this->expend, $profit];
}
}
BeijingFactory.php
<?php
namespace com\wdqz\decorate;
/**
* 北京工厂
*/
class BeijingFactory extends SettleDecorator
{
/**
* 收入金额
*/
public function revenue()
{
$revenue = 5000000.89;
if (empty($this->settle)) {
return $revenue;
}
$this->revenue = $revenue + $this->settle->revenue();
return $this->revenue;
}
/**
* 支出金额
*/
public function expend()
{
$expend = 3000000.32;
if (empty($this->settle)) {
return $expend;
}
$this->expend = $expend + $this->settle->expend();
return $this->expend;
}
}
ShanghaiFactory.php
<?php
namespace com\wdqz\decorate;
/**
* 上海工厂
*/
class ShanghaiFactory extends SettleDecorator
{
/**
* 收入金额
*/
public function revenue()
{
$revenue = 8000000.43;
if (empty($this->settle)) {
return $revenue;
}
$this->revenue = $revenue + $this->settle->revenue();
return $this->revenue;
}
/**
* 支出金额
*/
public function expend()
{
$expend = 2000000.98;
if (empty($this->settle)) {
return $expend;
}
$this->expend = $expend + $this->settle->expend();
return $this->expend;
}
}
NanjingFactory.php
<?php
namespace com\wdqz\decorate;
/**
* 南京工厂
*/
class NanjingFactory extends SettleDecorator
{
/**
* 收入金额
*/
public function revenue()
{
$revenue = 2000000.29;
if (empty($this->settle)) {
return $revenue;
}
$this->revenue = $revenue + $this->settle->revenue();
return $this->revenue;
}
/**
* 支出金额
*/
public function expend()
{
$expend = 4000000.52;
if (empty($this->settle)) {
return $expend;
}
$this->expend = $expend + $this->settle->expend();
return $this->expend;
}
}
ChengduFactory.php
<?php
/**
* 成都工厂
*/
class ChengduFactory extends \com\wdqz\decorate\SettleDecorator
{
/**
* 收入金额
*/
public function revenue()
{
$revenue = 1000000.29;
if (empty($this->settle)) {
return $revenue;
}
$this->revenue = $revenue + $this->settle->revenue();
return $this->revenue;
}
/**
* 支出金额
*/
public function expend()
{
$expend = 2000000.52;
if (empty($this->settle)) {
return $expend;
}
$this->expend = $expend + $this->settle->expend();
return $this->expend;
}
}
test.php
<?php
require_once('../../../autoloader.php');
use com\wdqz\decorate\BeijingFactory;
use com\wdqz\decorate\ShanghaiFactory;
use com\wdqz\decorate\NanjingFactory;
$decorator = new BeijingFactory(
new ShanghaiFactory(
new NanjingFactory(
new ChengduFactory(null)
)));
// 开始统计收支
$decorator->revenue();
$decorator->expend();
// 结果
$result = $decorator->result();
echo '宝马公司本年度总收入:'.$result[0].PHP_EOL;
echo '宝马公司本年度总支出:'.$result[1].PHP_EOL;
echo '宝马公司本年度总利润:'.$result[2].PHP_EOL;
效果
作者:Wolf 创建时间:2023-11-25 21:33
最后编辑:Wolf 更新时间:2023-11-27 23:47
最后编辑:Wolf 更新时间:2023-11-27 23:47