工厂中的重复条件语句

时间:2016-10-28 11:57:37

标签: php design-patterns factory factory-pattern

如何摆脱它们?我想知道是否存在解决此问题的模式或问题。基本上我需要根据另一个类的type属性实例化一个具体的子类,即如果type = 1则为new A,否则如果type = 2则为new B.等我最终得到了这种工厂在具有type属性的类中:

/**
 * Get a ticket decorator based on the ticket type
 * @return ReferralService\TicketDecorator
 * @throws Exception
 */
public function getTicketDecorator(): ReferralService\TicketDecorator
{
    if (!$this->code) {
        throw new Exception("Couldn't create a ticket wrapper based on the type without a code");
    }

    /**
     * The debug service
     * @var Debug\Service $debugService
     */
    $debugService = app(Debug\Service::class);
    $debugService->setDebug(config('referral.debug'));

    switch ($this->code) {
        case self::TYPE_FEEDBACK:
            return new ReferralService\TicketDecorator\FeedbackTicketDecorator($debugService);
            break;
        case self::TYPE_BIRTHDAY:
            return new ReferralService\TicketDecorator\BirthdayTicketDecorator($debugService);
            break;
        case self::TYPE_NEW_PARTNER:
            return new ReferralService\TicketDecorator\PartnerTicketDecorator($debugService);
            break;
        default:
            throw new Exception(sprintf("Couldn't instantiate a ticket decorator based on the %s type", $this->code));

    }
}

/**
 * Instantiate a private page based on the ticket type
 * @param ReferralService\Service $service
 * @param Referrer $referrer
 * @param Ticket $ticket
 * @return ReferralService\Page\PrivatePage
 * @throws Exception
 */
public function getPrivatePage(ReferralService\Service $service, Referrer $referrer, Ticket $ticket): ReferralService\Page\PrivatePage
{
    if (!$this->code) {
        throw new Exception("Couldn't create a private page based on the type without a code");
    }

    switch ($this->code) {
        case self::TYPE_FEEDBACK:
            return new ReferralService\Page\PrivatePage\EmailReference($this->service, $referrer, $ticket);
            break;
        case self::TYPE_BIRTHDAY:
            return new ReferralService\Page\PrivatePage\Birthday($this->service, $referrer, $ticket);
            break;
        case self::TYPE_NEW_PARTNER:
            return new ReferralService\Page\PrivatePage\Partner($this->service, $referrer, $ticket);
            break;
        default:
            throw new Exception(sprintf("Could't find a page for the type", $this->code));
    }
}

工厂中的每个方法都会测试类型字段,这对我来说看起来很笨拙。我想为每种类型都有一个单独的子类,并使用没有条件语句的工厂方法,但我不能用Laravel模型这样做。

2 个答案:

答案 0 :(得分:1)

这是replace conditionals by polymorphism非常常见的重构模式。

您可以实施工厂来创建专门的TicketType并在故障单类型上实施工厂方法,以创建具体的TicketDecoratorPrivatePage

但是,请记住,这确实引入了TicketType与它创建的具体类之间的耦合。如果最好避免这种耦合,那么坚持你的初始设计。

答案 1 :(得分:1)

嗯,这是我的解决方案。我已将TicketType(来自原始帖子的类与条件语句)从所有内容中解耦,因此它不知道页面/装饰器。

与此同时,我创建了具体的故障单类:BirthdayTicketPartnerTicket

我已将工厂方法放入Ticket类中,该类根据故障单类型生成故障单类的具体实例 - BirthdayTicketPartnerTicket具体的票证类使用上面@plalx建议的多态性来生成我需要的东西(页面,装饰器)。