Модифікована схема розробки стратегії


11

Я нещодавно почав розглядати шаблони дизайну, і одне, що я кодую, цілком відповідала б шаблону стратегії, за винятком однієї невеликої різниці.

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

Тож мені або потрібно буде

  • передайте їм додатковий параметр, коли я викликаю їхній метод обчислення

або

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

Чи існує модель дизайну для цієї потреби / Як я можу це реалізувати, дотримуючись Шаблону стратегії?

Я розглядав можливість передачі клієнтського об'єкта всім алгоритмам і зберігання там змінних, а потім використовувати його лише тоді, коли конкретний алгоритм цього потребує. Однак я вважаю, що це одночасно і непросто, і перемагає точку стратегії.

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


Необов’язкові параметри, як у C ++, нічого не вирішать, оскільки вони є лише скороченням для визначення декількох перевантажених методів.
maaartinus

Я б дуже старався уникати збереження додаткових параметрів десь там, де мені довелося їх змінити перед використанням. Таким чином ви робите ConcreteAlgorithm стаціонарним, тому його не можна легко передати іншому методу чи потокам. Більше того, занадто просто забути встановити параметри.
maaartinus

Відповіді:


5

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

Напр

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 Я теж бачу занепад. Але я не бачу кращих способів. Не могли б ви вказати на краще рішення? Стаття чи щось таке?
Нарек

Власне, так. @ Джордао має відповідь, яку я вважаю за краще, виходячи з деталей, які ми маємо в питанні. Ця відповідь відповідає сильним сторонам стратегії. Якби у цій відповіді ми пішли з підходом, я хотів би StrategyParameterмістити всі можливі параметри, як DTO. Деякі реалізації стратегії можуть їх ігнорувати. У деяких випадках це найкращий підхід. Контекст є важливим для цих питань.
високий

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

Поширюючись на вищезазначену відповідь, надану пікітом - можна використовувати абстракцію. Я тут використовую код пікіту -

Інтерфейс MyStrategy { абстрактний недійсний myStrategyMethod (параметр StrategyParameter); }

клас MyNormalStrategy розширює MyStrategy {public override void myStrategyMethod (параметр StrategyParameter) {// реалізувати тут логіку}}

клас MySpecializedStrategy розширює MyStrategy {public override void myStrategyMethod (параметр StrategyParameter, ExtraStrategyParameter extraParameter) {// реалізувати логіку тут} }

Якщо я правильно розумію ваше запитання, ви хотіли передати додатковий параметр певним алгоритмам? Будь ласка, дайте мені знати, якщо це те, що ви шукали?


0

Якщо ви заглянете до книги "Шаблони дизайну", то не є помилковим, що існує деяка SimpleStrategy, яка використовує менше або жоден з переданих параметрів, або що параметри є множником одного розміру-підходить-всі / найменше-загального. Вибір дизайну тут полягає в тому, чи не зашкодить це вам з точки зору додаткової обробки, яка в кінцевому підсумку не використовується.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.