我该如何解决这个OOP设计问题?

时间:2011-01-17 16:19:26

标签: php oop design-patterns

我的系统有3个组件:

报告 - 包含用于定义报告实际包含在其输出中的内容的逻辑。示例包括TopMerchantsReportLowestTransactionsReport

ReportRunner - 由于报告仅进行数据收集和生成,因此该类负责运行所有报告并调度结果(例如,通过电子邮件)。每个Report都有自己的ReportRunner

ReportProfile - 包含特定报告的用户设置的数据库表的对象镜像。


Report可以有多种可插入行为,例如Digestable和/或Schedulable。由于PHP没有mixins,因此最好用装饰器模式表示。

我的实际问题是,当关联的Report使用Schedulable之类的内容进行修饰时,这三个对象中的每一个都需要修改其行为。例如,ReportRunner现在只需收集预定报告,而ReportProfile将受益于isScheduled()方法。

我不想强迫用户必须装饰所有3个类。这不仅容易出错,而且我必须为每个行为创建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一起使用的那个。