Эта Стратегическая модель Java имеет избыточный класс Контекста?

Следующий пример кода является реализацией Стратегической модели, скопированной с Википедии. Мой полный вопрос следует за ним...

Wiki main метод:

//StrategyExample test application

class StrategyExample {

    public static void main(String[] args) {

        Context context;

        // Three contexts following different strategies
        context = new Context(new ConcreteStrategyAdd());
        int resultA = context.executeStrategy(3,4);

        context = new Context(new ConcreteStrategySubtract());
        int resultB = context.executeStrategy(3,4);

        context = new Context(new ConcreteStrategyMultiply());
        int resultC = context.executeStrategy(3,4);

    }

}

Части шаблона:

// The classes that implement a concrete strategy should implement this

// The context class uses this to call the concrete strategy
interface Strategy {

    int execute(int a, int b);

}

// Implements the algorithm using the strategy interface
class ConcreteStrategyAdd implements Strategy {

    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategyA's execute()");
        return a + b;  // Do an addition with a and b
    }

}

class ConcreteStrategySubtract implements Strategy {

    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategyB's execute()");
        return a - b;  // Do a subtraction with a and b
    }

}

class ConcreteStrategyMultiply implements Strategy {

    public int execute(int a, int b) {
        System.out.println("Called ConcreteStrategyC's execute()");
        return a  * b;   // Do a multiplication with a and b
    }

}

// Configured with a ConcreteStrategy object and maintains a reference to a Strategy object
class Context {

    private Strategy strategy;

    // Constructor
    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public int executeStrategy(int a, int b) {
        return strategy.execute(a, b);
    }

}

При рассмотрении конкретно вышеупомянутого примера, Context избыточный класс?

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

((Редактирование: В этом простом сценарии, когда я не учту класс Контекста, я буду делать будущую ошибку?))

public static void main(String[] args) {

    IStrategy strategy;

    // Three strategies
    strategy = new ConcreteStrategyAdd();
    int resultA = strategy.executeStrategy(3,4);

    strategy = new ConcreteStrategySubtract();
    int resultB = strategy.executeStrategy(3,4);

    strategy = new ConcreteStrategyMultiply();
    int resultC = strategy.executeStrategy(3,4);

}

Сводное обновление

Список в точке формирует то, что было обнаружено через ответы и комментарии:

  • Контекст допускает вариацию в том, как составленная Стратегия используется (например, синхронизация, он - вызов). Различные Контексты могли бы сделать другую внутреннюю работу прежде и после вызова данной Стратегии.
  • Контекст является "черным квадратом" высокого уровня. Логика Контекста может измениться, также составленная Стратегия может измениться (или другая используемая), не повреждая клиент, потому что клиент понимает только, как назвать контекст.
  • Даже при том, что я создал альтернативную реализацию примера кода Википедии путем игнорирования Контекста, и хотя это работало то же оригиналом, вся ситуация была упрощена (в обоих случаях) и мои изменения, на самом деле предназначенные: 1. это больше не Стратегическая модель, 2. Я пропускаю преимущества духа Стратегической модели, которые упоминаются здесь.
  • Моя альтернативная реализация использовала основной метод как Контекст, таким образом, я мог бы также сохранить Контекст, эффективно моделировав его. Путем создания нечистой Стратегической модели был создан беспорядок. Я не должен был изобретать велосипед или пытаться быть более умным (в этом случае).

Если какие-либо другие точки были бы полезны или если этому нужен отпуск исправления комментарий, и я изменю список соответственно.

14
задан John K 6 January 2010 в 05:15
поделиться

3 ответа

Как следует из названия, Context - это то, что инкапсулирует точку, в которой осуществляется стратегия. Без этого у вас просто голая стратегия , и вызывающий класс теперь берет на себя дополнительную ответственность: знать, когда вызывать саму стратегию . Ваш пример, пожалуй, слишком прост, и в данном конкретном случае, Я бы сказал, что Context не слишком многого добивается.

Пример, который, возможно, лучше иллюстрирует полезность Context, больше похож на следующий:

public class LoadingDock {   // Context.
  private LoadStrategy ls;   // Strategy.

  public void setLoadStrategy(LoadStrategy ls) { ... }

  // Clients of LoadingDock use this method to do the relevant work, rather
  // than taking the responsibility of invoking the Strategy themselves.
  public void shipItems(List<ShippingItem> l) {
    // verify each item is properly packaged     \
    // ...                                        |  This code is complex and shouldn't be
    // verify all addresses are correct           |  subsumed into consumers of LoadingDock.
    // ...                                        |  Using a Context here is a win because
    // load containers onto available vehicle     |  now clients don't need to know how a
    Vehicle v = VehiclePool.fetch();        //    |  LoadingDock works or when to use a
    ls.load(v, l);                          //   /   LoadStrategy.
  }
}

Заметьте, как Strategy никогда не будет вызываться напрямую от внешнего клиента. Только shipItems использует эту стратегию, а детали последующих шагов - это черный ящик. Это позволяет Context настроить, как она использует стратегию, не затрагивая клиентов. Например, шаги могут быть полностью переупорядочены или скорректированы (или полностью удалены) для достижения целей производительности или других целей -- но для клиента внешний интерфейс shipItems() выглядит точно так же.

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

.
16
ответ дан 1 December 2019 в 12:26
поделиться

Это лучший пример того, как реальный "Context " класс может выглядеть в этом сценарии:

class Accumulator {
    private Strategy strategy; 

    public Accumulator(Strategy strategy) { 
        this.strategy = strategy; 
    } 

    public int accumulate(List<Integer> values) { 
        int result = values.get(0);
        for (int i = 1; i < values.size(); i++) {
           result = strategy.execute(result, values.get(i));
        }
        return result;
    } 
}

EDIT: Typo в конструкторе fix

.
4
ответ дан 1 December 2019 в 12:26
поделиться

Это может быть и для вымышленного примера, но тогда я бы не стал называть это ne plus ultra из Strategy.

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

То, как вы это закодировали, сработает, но суть в том, что вы выкинули это в основной метод. Это будет не тот способ, которым вы обычно используете Strategy. Вы будете делать это внутри класса, и Context является простым примером этого.

3
ответ дан 1 December 2019 в 12:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: