什么是组合模式?
- 科学术语:将一组对象组合为可像单个对象一样使用的结构。
- 自我理解:看到组合模式,可以理解成一棵树,树根是接口,其他的都是叶子(具体实现),有的叶子是局部对象,有的是组合对象,这个组合对象就是组合模式的主要实现。可以结合下面的代码来理解。
注意事项
- 组合模式是将继承用于组合对象的最极端的例子。意思是,这个模式很容易理解,并且你会不自觉的想到处使用它。但其实每一个模式,只是一种策略,它并不适合每一个业务场景。
具体实现
- 实例场景1:宝马公司的老板要求财务出一个报表,能够实时的看到世界各地工厂的收支情况。(最终会交给IT部门)
- 这个需求的目标很简单,通过各工厂提供的财务收支表,最后分类汇总即可。
- 实例场景2:开发游戏的过程中,敌对双方的血槽值/战斗力实时计算模块。
- 战斗单元是基础单元接口,其余实现类要么是局部对象(单一功能),要么是组合对象。
- UML图
代码实例
因篇幅有限,代码只实现场景1,有兴趣的朋友可以自己实现场景2
Settle.php
<?php
namespace com\wdqz\combination;
/**
* 组合模式-结算接口
* - 宝马公司的需求是收支结算,这里结算工具将成为各分厂的基本单元
*
* @author woodhead
* @date 2023年11月24日16:25:14
*/
interface Settle
{
/**
* 添加分厂结算
* @return mixed
*/
public function addSettle(Settle $settle);
/**
* 收入
* @return mixed
*/
public function revenue();
/**
* 支出
* @return mixed
*/
public function expend();
/**
* 计算收支差
* @return mixed
*/
public function calc();
}
BeijingFactory.php
<?php
namespace com\wdqz\combination;
/**
* 宝马北京工厂
*
* @author woodhead
* @date 2023年11月24日16:28:33
*/
class BeijingFactory implements Settle
{
/**
* 添加分厂结算
* - 因自身已经是分厂,不再执行具体逻辑
*
* @param Settle $settle
* @return false
*/
public function addSettle(Settle $settle)
{
return false;
}
/**
* 收入金额
* @return float
*/
public function revenue()
{
return 5000000.89;
}
/**
* 支出金额
* @return float
*/
public function expend()
{
return 3000000.32;
}
/**
* 计算收支差
* @return float
*/
public function calc()
{
return floatval(bcsub($this->revenue($this), $this->expend($this), 2));
}
}
ShanghaiFactory.php
<?php
namespace com\wdqz\combination;
/**
* 宝马上海工厂
*
* @author woodhead
* @date 2023年11月24日16:28:33
*/
class ShanghaiFactory implements Settle
{
/**
* 添加分厂结算
* - 因自身已经是分厂,不再执行具体逻辑
*
* @param Settle $settle
* @return false
*/
public function addSettle(Settle $settle)
{
return false;
}
/**
* 收入金额
* @return float
*/
public function revenue()
{
return 8000000.43;
}
/**
* 支出金额
* @return float
*/
public function expend()
{
return 2000000.98;
}
/**
* 计算收支差
* @return float
*/
public function calc()
{
return floatval(bcsub($this->revenue($this), $this->expend($this), 2));
}
}
HeadFactory.php
<?php
namespace com\wdqz\combination;
/**
* 总厂
* - 组合模式的核心
* - 负责局部对象的整合
* - 负责最终整体结算
*/
class HeadFactory implements Settle
{
/**
* @var array 分厂列表
*/
private $factoryList = [];
/**
* 添加分厂结算
* - 总厂将组合分厂
*
* @return void
*/
public function addSettle(Settle $settle)
{
if (in_array($settle, $this->factoryList, true)) {
return;
}
$this->factoryList[] = $settle;
}
/**
* 收入金额
* @return float
*/
public function revenue()
{
$resultAmount = 0.00;
foreach ($this->factoryList as $factory) {
$resultAmount += $factory->revenue();
}
return $resultAmount;
}
/**
* 支出金额
* @return float
*/
public function expend()
{
$resultAmount = 0.00;
foreach ($this->factoryList as $factory) {
$resultAmount += $factory->expend();
}
return $resultAmount;
}
/**
* 计算收支差
* @return float
*/
public function calc()
{
$resultAmount = 0.00;
foreach ($this->factoryList as $factory) {
$resultAmount += $factory->calc();
}
return $resultAmount;
}
}
test.php
<?php
require_once('../../../autoloader.php');
use com\wdqz\combination\HeadFactory;
use com\wdqz\combination\BeijingFactory;
use com\wdqz\combination\ShanghaiFactory;
// 总厂对象
$headFactory = new HeadFactory();
// 添加北京分厂结算对象
$headFactory->addSettle(new BeijingFactory());
// 添加上海分厂结算对象
$headFactory->addSettle(new ShanghaiFactory());
// 计算公司收支+利润
echo '宝马公司本年度总收入:'.$headFactory->revenue().PHP_EOL;
echo '宝马公司本年度总支出:'.$headFactory->expend().PHP_EOL;
echo '宝马公司本年度总利润:'.$headFactory->calc().PHP_EOL;
效果
作者:Wolf 创建时间:2023-11-24 00:31
最后编辑:Wolf 更新时间:2023-11-27 23:47
最后编辑:Wolf 更新时间:2023-11-27 23:47