【问题标题】:Multiple Strategies in Strategy Pattern Context策略模式上下文中的多种策略
【发布时间】:2018-08-02 17:19:27
【问题描述】:

我对策略模式有疑问。通常策略模式是这样的:

class TaxCalculatorContext
{
    private $strategy;

    public function setStrategy(TaxCalculatorStrategyInterface $strategy)
    {
        $this->strategy = $strategy;
    }

    public function execute($amount)
    {
        return $this->strategy->calculate($amount);
    }
}

class TaxCalculatorOntario implements TaxCalulatorStrategyInterface
{
    public function calculate($amount)
    {
        ...calculate ontario taxes here
    }
}

class TaxCalculatorQuebec implements TaxCalculatorStrategyInterface
{
    public function calculate($amount)
    {
        ...calculate quebec taxes here
    }
}

interface TaxCalculatorStrategyInterface
{
    public function calculate($amount);
}

我想知道在一个上下文中使用多种策略是否是一种可接受的做法。请看下面的代码。

class TaxCalculatorContext
{
    private $strategies;

    public function addStrategy(TaxCalculatorStrategyInterface $strategy)
    {
        $this->strategies[] = $strategy;
    }

    public function execute($amount)
    {
        foreach ($this->strategies as $strategy)
        {
            if($strategy->canCalculate)
            {
                return $strategy->calculate($amount);
            }
        }
    }
}

class TaxCalculatorOntario implements TaxCalulatorStrategyInterface
{
    public function canCalculate($amount)
    {
        ... returns true or false
    }

    public function calculate($amount)
    {
        ...calculate ontario taxes here
    }
}

class TaxCalculatorQuebec implements TaxCalculatorStrategyInterface
{
    public function canCalculate($amount)
    {
        ... returns true or false
    }

    public function calculate($amount)
    {
        ...calculate quebec taxes here
    }
}

interface TaxCalculatorStrategyInterface
{
    public function canCalculate($amount);
    public function calculate($amount);
}

如您所见,我不是只传递一个策略,而是在 TaxCalculatorContext 中创建了一组策略。然后,当调用 execute 方法时,策略会被循环,第一个在 canCalulate 方法中返回 true 的策略将被执行。那么这是一种标准做法还是我应该避免它?

【问题讨论】:

    标签: php oop strategy-pattern


    【解决方案1】:

    如果它适合您的问题,那么我看不出您有任何不这样做的理由。如果您要将其改造成现有的策略结构,那么您可以使用复合模式进行调查。您将使用它的方式是创建一个新的策略子类,该子类接受多个 other 策略到它的构造函数或工厂。然后,在策略本身内部,它将根据需要执行子策略。这样一来,您无需更改 Strategy 接口,调用该策略的客户端代码也无需知道甚至 多个策略。

    但是,如果您不进行改造,并且拥有多种策略的想法是问题域不可或缺的一部分,那么您可以避免实施 Composite 带来的额外复杂性,并按照您的指示进行操作。向一个事物抛出越来越多的模式并不总是必要的,或者在速度方面是有效的。如果您想将多种策略的想法与客户端代码分离,只需知道 Composite 可以作为未来重构的一个选项。

    关于您给出的示例的两点评论(您可能已经知道,但以防万一):首先,正如当前所写的那样,多个策略示例将执行谓词返回 true 的 每个 策略,而不仅仅是第一个(如果您希望这种行为,则在计算第一个之后需要一个 break 语句)。其次,分散在应用程序周围的状态越多,潜在的错误就越多。因此,可能需要考虑从 Strategy::calculate() 中返回计算值,而不是像当前接口所暗示的那样将其存储在策略中。这将使您的策略成为无状态函子,这是可取的,因为这样您就不必考虑管理它们的状态。

    【讨论】:

    • 感谢您的评论!我忘记在我的代码示例中添加上下文中的 return 语句,我现在就做。
    • 不客气!是的,你说得对,我之前的回复更多的是评论而不是答案......我已经将其更新为更“回答”:)