我的系统有3个组件:
报告 - 包含用于定义报告实际包含在其输出中的内容的逻辑。示例包括TopMerchantsReport
和LowestTransactionsReport
。
ReportRunner - 由于报告仅进行数据收集和生成,因此该类负责运行所有报告并调度结果(例如,通过电子邮件)。每个Report
都有自己的ReportRunner
。
ReportProfile - 包含特定报告的用户设置的数据库表的对象镜像。
Report
可以有多种可插入行为,例如Digestable
和/或Schedulable
。由于PHP没有mixins,因此最好用装饰器模式表示。
我的实际问题是,当关联的Report
使用Schedulable
之类的内容进行修饰时,这三个对象中的每一个都需要修改其行为。例如,ReportRunner
现在只需收集预定报告,而ReportProfile
将受益于isScheduled()
方法。
我不想强迫用户必须装饰所有3个类。这不仅容易出错,而且我必须为每个行为创建3个装饰器(每个类一个)。还有什么其他解决方案?
答案 0 :(得分:0)
class Report{
const SCHEDULED = 1;
const DIGESTABLE = 2;
private $behaviour;
public function getReportData(){}
public function getReportProfile(){}
public function getBehaviour(){
return $this->behaviour;
}
}
class ReportRunner{
public function runReport(){
switch($this->report->getBehaviour()){
case Report::SCHEDULED
//do sheduled stuff
case Report::DIGESTABLE
//do DIGESTABLE stuff
}
}
}
答案 1 :(得分:0)
如果你想要一个具体的例如在其他两个组件中报告不同的行为,你必须最终装饰它们,所以你无法避免这种情况。迁移的唯一问题是根据选择的行为管理要装饰的那三个组件的创建,例如消化的。这可以使用工厂方法模式来完成,它允许您创建所有这三个组件的适当类型。
答案 2 :(得分:0)
我唯一可以想到的是,如果我理解你的考验,就是使用工厂设计。工厂有责任根据其装饰提供与特定报告对应的ReportRunner和ReportProfile。
因此,每个ReportRunner都有一个类,ReportProfile有一个类,非常相似。
ReportRunner Factory 应该有一个接受Report的装饰并返回它的ReportRunner的方法,所以你可以这样做:
report->setReportRunner( factoryReportRunner->getReportRunner(report->getDecorationType() );
在FactoryReportRunner类中,你有一个 getReportRunner(...)
的方法getReportRunner(decorationType){
$functionToCall = $this->'get'.decorationType.'ReportRunner';
if(function_exists($functionToCall) &&
is_callable(array($this, $functionToCall))){
return $this->$functionToCall();
}else{
//log or alert as error
}
}
当然,您必须为每种装饰类型设置 getDecorationReportRunner ,在这种情况下: getDigestableReportRunner 和 getSchedulableReportRunner 。 ReportProfile的工厂也是如此。这样,每当您添加新的装饰类型时,您只需要添加相应的 getDecorationReportRunner 以及与ReportProfile一起使用的那个。