什么是装饰模式?

  • 装饰模式是组合+委托的变种,也就是在组合模式的基础上,在装饰类的构造函数中,增加了对象委托。

应用场景

  • 和组合模式一样,因为它的优雅和易理解,所以在很多场景下都适用。

注意事项

  • 唯一需要注意的地方就是不要过度使用。

具体实现

  • 和组合模式的不同点:组合在于局部对象和组合对象,装饰在于委托;组合在于对局部对象的组合,装饰在于对子类对象的委托。
  • 实例场景:还是延续宝马老板的要求,要求财务出实时报表,查看各个工厂的收支、利润情况。
  • 组合模式中,组合类对局部对象进行了统一 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