Модифицированный шаблон дизайна стратегии


11

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

По сути, некоторые (но не все) из моих алгоритмов нуждаются в дополнительном параметре или двух передаваемых им.

Так что мне либо нужно

  • передать им дополнительный параметр, когда я вызываю их метод вычисления

или же

  • сохраните их как переменные внутри класса ConcreteAlgorithm и сможете обновить их, прежде чем я вызову алгоритм.

Существует ли шаблон проектирования для этой потребности / Как я могу реализовать это, придерживаясь шаблона стратегии?

Я рассмотрел передачу объекта client во все алгоритмы и сохранение там переменных, а затем использовал его только тогда, когда это требуется конкретному алгоритму. Тем не менее, я думаю, что это и громоздко, и побеждает смысл стратегии.

Просто чтобы прояснить, я реализую в Java, и поэтому не могу позволить себе роскошь дополнительных параметров (что решило бы это хорошо).


Необязательные параметры, такие как в C ++, ничего не решат, так как они являются просто сокращением для определения нескольких перегруженных методов.
Maaartinus

Я бы постарался избежать хранения дополнительных параметров где-то, где мне пришлось изменить их перед использованием. Таким образом вы делаете ConcreteAlgorithm сохраняющим состояние, чтобы его нельзя было легко передать другому методу или потокам. Кроме того, слишком легко забыть установить параметры.
Maaartinus

Ответы:


5

Сэмюэль, возможно ли инкапсулировать параметр, который каждая из стратегий принимает в один общий класс, и затем расширить этот общий класс Parameter, чтобы добавить больше поведения, которое особенно необходимо для некоторых из ваших стратегий?

Например

StrategyParameter //Base strategy parameter that most of the strategies need
        ^
        |
        |
SpecialStrategyParameter // will be used for strategies that need more parameter

Затем определите иерархию стратегии, например:

Interface MyStrategy {
   void myStrategyMethod(StrategyParameter parameter);
}

class MyNormalStrategy extends MyStrategy {
   void myStrategyMethod(StrategyParameter parameter) {
       //implement the logic here
   }
}

назвать вышеуказанную стратегию как: myNormalStrategyInstance.myStrategyMethod(strategyParameter);

class MySpecializedStrategy extends MyStrategy {
   void myStrategyMethod(StrategyParameter parameter) {
       //implement the logic here
   }
}

вызвать вышеупомянутую стратегию, передавая SpecialStrategyParameterэкземпляр вместо:mySpecializedStrategy.myStrategyMethod(specialStrategyParameter);

Пожалуйста, обновите, если что-то не понятно. Будем рады объяснить / уточнить.


2
-1 требует понижения, нарушает инкапсуляцию дизайна. Хотя в данном вопросе речь идет об улучшении дизайна, существуют более эффективные способы снятия кожи с этой кошки.
Tallseth

@tallseth я тоже вижу удрученным. Но я не вижу лучших путей. Не могли бы вы указать лучшее решение? Статья или что-то?
Нарек

На самом деле да. У @ Jordão есть ответ, который я бы предпочел, основываясь на деталях, которые у нас есть в вопросе. Этот ответ играет на сильных сторонах стратегии. Если бы мы пошли с подходом в этом ответе, я бы хотел StrategyParameterсодержать все возможные параметры, как DTO. Некоторые реализации стратегии могут их игнорировать. В некоторых случаях это лучший подход. Контекст является королем для такого рода вопросов.
Tallseth

4

Вам необходимо уточнить вашу стратегию .

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

Ранее я использовал настраиваемые стратегии, в которых вы параметризовали конкретные классы построения:

interface Strategy {
  int calculate();
}

class ConcreteStrategyThatNeedsAParameter implements Strategy {
  private final int param;
  public ConcreteStrategyThatNeedsAParameter(int param) {
    this.param = param;
  }
  public int calculate() { 
    // uses param...
  }
}

Теперь кому-то еще нужно создать экземпляр этого класса и передать его вашему клиенту. Но вашему клиенту все еще нужно знать об Strategyинтерфейсе.

Это также работает, если ваш метод стратегии принимает параметры, но тогда ваш клиент знает об этих параметрах и передает их всем реализациям, с которыми он работает.


Клиент - тот, у которого есть контекст для предоставления параметра.
andyczerwonka

1

Пока подпись определена на интерфейсе четко, она все еще соответствует шаблону Стратегии.

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


0

расширяя ответ выше, предоставленный peakit - вы можете использовать абстракцию. Я использую код Пикита здесь -

Интерфейс MyStrategy { abstract void myStrategyMethod (параметр StrategyParameter); }

класс MyNormalStrategy extends MyStrategy {публичное переопределение void myStrategyMethod (параметр StrategyParameter) {// реализовать логику здесь}}

класс MySpecializedStrategy extends MyStrategy {public override void myStrategyMethod (параметр StrategyParameter, ExtraStrategyParameter extraParameter) {// реализуем логику здесь} }

Если я правильно понимаю ваш вопрос, вы хотите передать дополнительный параметр некоторым алгоритмам, верно? Пожалуйста, дайте мне знать, если это то, что вы искали?


0

Если вы загляните в книгу «Шаблоны проектирования», то, по сути, нет ничего плохого в том, что существует какая-то SimpleStrategy, которая использует меньше или ни один из переданных параметров, или что параметры представляют собой множитель «один размер подходит для всех / наименьшего общего числа». Выбор дизайна в данном случае заключается в том, наносит ли это вам вред с точки зрения дополнительной обработки, которая в итоге не используется.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.