Php 我如何解决这个OOP设计问题?
我的系统有3个组件: 报表-包含用于定义报表在其输出中实际包含内容的逻辑。示例包括Php 我如何解决这个OOP设计问题?,php,oop,design-patterns,Php,Oop,Design Patterns,我的系统有3个组件: 报表-包含用于定义报表在其输出中实际包含内容的逻辑。示例包括TopMerchantsReport和LowestTransactionsReport ReportRunner-由于报表只收集和生成数据,此类负责运行所有报表并发送结果(例如,通过电子邮件)。每个报告都有自己的ReportRunner ReportProfile-包含特定报表的用户设置的数据库表的对象镜像 报告可以具有多个可插拔行为,例如可消化的和/或可可调度的。由于PHP没有mixin,因此最好用decora
TopMerchantsReport
和LowestTransactionsReport
ReportRunner-由于报表只收集和生成数据,此类负责运行所有报表并发送结果(例如,通过电子邮件)。每个报告
都有自己的ReportRunner
ReportProfile-包含特定报表的用户设置的数据库表的对象镜像
报告可以具有多个可插拔行为,例如可消化的
和/或可可调度的
。由于PHP没有mixin,因此最好用decorator模式来表示
我的实际问题是,当关联的报告
用类似于可调度
的东西修饰时,这3个对象中的每一个都需要修改其行为。例如,ReportRunner
现在只需要收集计划的报告,ReportProfile
将受益于isScheduled()
方法
我不想强迫用户装饰所有3个类。这不仅容易出错,而且我还必须为每个行为创建3个装饰器(每个类一个)。还有什么其他的解决方案?如果你想有一个具体的类,例如报告其他两个组件中的不同行为,你必须最终装饰它们,因此你无法避免。唯一的问题可能是管理这三个组件的创建,根据选择的行为进行装饰,例如可消化。这可以使用factory方法模式来完成,该模式允许您创建所有这三个组件的适当类型。如果您想要有一个具体的类,例如报告其他两个组件中的不同行为,您必须最终装饰它们,因此您无法避免。唯一的问题可能是管理这三个组件的创建,根据选择的行为进行装饰,例如可消化。这可以使用工厂方法模式来完成,它允许您创建所有这三个组件的适当类型。如果我正确理解您的痛苦,我唯一能想到的就是使用工厂设计。工厂有责任提供与特定报告相对应的ReportRunner和ReportProfile(基于其装饰)
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
}
}
}
所以每个ReportRunner和ReportProfile都有一个类,非常相似
ReportRunner Factory应该有一个方法,该方法接受报表的装饰并返回其ReportRunner,因此您可以执行以下操作:
report->setReportRunner( factoryReportRunner->getReportRunner(report->getDecorationType() );
在FactoryReportRunner类中,您将有一个方法getReportRunner(…)
当然,对于每种装饰类型,您都必须有一个getDecorationReportRunner,在本例中:getDigestableReportRunner和getSchedulableReportRunner。ReportProfile的工厂也是如此。这样,每当添加新的装饰类型时,只需添加相应的getDecorationReportRunner和ReportProfile附带的装饰类型 如果我能正确理解你的痛苦,我唯一能想到的就是使用工厂设计。工厂有责任提供与特定报告相对应的ReportRunner和ReportProfile(基于其装饰)
所以每个ReportRunner和ReportProfile都有一个类,非常相似
ReportRunner Factory应该有一个方法,该方法接受报表的装饰并返回其ReportRunner,因此您可以执行以下操作:
report->setReportRunner( factoryReportRunner->getReportRunner(report->getDecorationType() );
在FactoryReportRunner类中,您将有一个方法getReportRunner(…)
当然,对于每种装饰类型,您都必须有一个getDecorationReportRunner,在本例中:getDigestableReportRunner和getSchedulableReportRunner。ReportProfile的工厂也是如此。这样,每当添加新的装饰类型时,只需添加相应的getDecorationReportRunner和ReportProfile附带的装饰类型