Несколько стратегий в контексте шаблонов стратегий

У меня есть вопрос о шаблоне стратегии. Обычно шаблон стратегии выглядит следующим образом:

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, стратегии зацикливаются, и первая из них, которая возвращает true в методе canCalulate, будет выполнена. Так это стандартная практика или я должен избегать этого?

1

Решение

Если это устраивает вашу проблему, то я не вижу причин, по которым вы бы этого не сделали. Если вы модифицируете это в существующую стратегическую структуру, то вы можете исследовать, используя шаблон Composite. То, как вы могли бы использовать это, чтобы создать новый подкласс стратегии, который принимает несколько Другой стратегии для его конструктора или фабрики. Затем, внутри самой стратегии, он будет выполнять субстратегии по мере необходимости. Таким образом, вам не нужно менять интерфейс стратегии, и клиентский код, который вызывает стратегию, не должен знать, что там даже являются несколько стратегий.

Но если вы не модернизируете, и идея наличия нескольких стратегий является неотъемлемой частью проблемной области, тогда вы, возможно, можете избежать дополнительной сложности реализации Composite и просто продолжить, как вы указали. Бросать все больше и больше узоров в вещь не всегда необходимо или эффективно с точки зрения скорости. Просто знайте, что Composite существует как опция для будущего рефакторинга, если вы когда-нибудь захотите отделить идею нескольких стратегий от клиентского кода.

Два замечания о приведенном вами примере (который вы, возможно, уже знаете, но на всякий случай): во-первых, как написано в настоящее время, будет выполнен пример нескольких стратегий. каждый Стратегия, предикат которой возвращает true, а не только первый (вам нужен оператор break после вычисления первого, если вы хотите такое поведение). Во-вторых, чем больше состояний вы разбросали по своему приложению, тем больше потенциальных ошибок вы будете иметь. Поэтому, возможно, стоит подумать о том, чтобы вернуть вычисленное значение обратно из Strategy :: Calculate (), а не сохранять его в стратегии, как в настоящее время подразумевает интерфейс. Это превратит ваши стратегии в функторы без сохранения состояния, что желательно, потому что тогда вам не нужно думать об управлении их состоянием.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]