Подтвердить что ты не робот

Когда использовать метод шаблона Vs. Стратегия?

Шаблон метода шаблона и шаблон стратегии делают примерно одно и то же. Я понимаю основные различия между ними (метод шаблона основан на наследовании, стратегия основана на композиции), но есть ли какие-то достойные рекомендации о том, когда выбирать один над другим? Похоже, они делают в основном то же самое.

4b9b3361

Ответ 1

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

Во всех остальных случаях (например, когда алгоритм должен использовать интерфейс объекта), я пытаюсь использовать Стратегию.

Кроме того, стратегия применима только тогда, когда существуют реальные алгоритмы для реализации: если единственная разница между классами (например), какое простое значение возвращает, используйте метод Template.

Ответ 2

Стратегия

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

Метод шаблона специально предназначен для тех случаев, когда вы хотите, чтобы люди могли наследовать ваш класс и хотели, чтобы они могли переопределить вашу реализацию контролируемым образом (в основном, чтобы они не заменили всю вашу сантехнику и не предложили им конкретную точки расширения, не рискуя проблемой, потому что они не вызвали базовый метод или не вызвали его в неподходящее время).

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

Ответ 3

Эти два могут фактически эффективно использоваться вместе.

Не думайте о шаблонах как рецептах с определенным кодом для их реализации.

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

Метод шаблона дает вам "алгоритм со сменными шагами". (Алгоритм обычно определяется неперехватывающим методом (например, конечным или частным))

В реализации этой концепции GoF используется наследование и метод, переопределяющие эти шаги.

Однако вы все еще используете метод Template, если эти шаги заменены стратегиями.

Например, подумайте о классе, который хочет ходить по двоичному дереву inorder и "делать что-то" на каждом node.

Цель состоит в том, что метод inorder() является методом шаблона - структура ходьбы всегда одна и та же.

Метод "hook", часть, которая "делает что-то", может быть реализована как метод в том же классе (и переопределена в подклассах для изменения поведения) или внешне, и в этом случае это стратегия "делать что-то",.

Ответ 4

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

  • Поведение вашего объекта должно быть изменено во время выполнения.
  • У вас уже есть иерархия классов по другим критериям.
  • Вы хотите делиться стратегической логикой между разными классами.

В других случаях достаточно использовать шаблон шаблона.

Ответ 5

Я не согласен с этим утверждением (от этого ответа):

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


Если вы хотите, чтобы люди наследовали от вашего класса, тогда вы WANTING для конкретной реализации, а не хотите определенного поведения. Это плохо пахнет мне.

Действительной вещью для ХОТИТЕ является возможность переопределить или обеспечить реализацию отдельных шагов алгоритма. Эта цель может быть достигнута с помощью обоих методов шаблонов (где мы можем выборочно переопределять защищенные методы) или шаблона стратегии (где мы внедряем реализации).

Если вы создаете класс, который реализует алгоритм, и вы хотите разрешить изменения в этом алгоритме другими разработчиками, это ваше требование. Ваше единственное решение - разрешить ли это делать это через наследование или состав.

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

Я бы никогда не начинал с "Я хочу разрешить им наследовать от этого класса". Эта тележка перед лошадью ИМО.

Ответ 6

Вы можете создать большое дерево наследования, чтобы изменить одно из действий N. И вы можете создать второе большое дерево наследования, чтобы изменить второе поведение N.

Но вы также можете разгрузить дерево, создав небольшие деревья стратегий.

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

Ответ 7

Я хотел бы согласиться и объяснить второе объяснение Скотта.

Шаблон pattern = заботится о том, чтобы рисовать общие строки, вдоль которых будет выполняться операция, - templating - в основном "алгоритм со сменными шагами" (очень хорошо придуман), где сменные шаги могут быть делегированы используя концепцию шаблона Стратегия.

Стратегия pattern = заботится только о том, чтобы развязать клиента с подчеркнутой реализацией операции, результат которой должен всегда выполняться некоторыми предопределенными правилами (например, сортировка, где результат всегда является отсортированным списком, но вы можете deffer фактической сортировки для сортировки пузыря или быстрого сортировки).

Приветствия.

Ответ 8

Одним из центральных принципов OO Design является "Преимущество композиции над наследованием", поэтому это говорит о предпочтительности шаблона стратегии. Очевидно, это зависит от того, что вы пытаетесь выполнить в конкретном сценарии.

Ответ 9

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

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

Ответ 10

Мое резюме: шаблон стратегии более-слабо связан, чем шаблон шаблона метода, что, как правило, хорошо.

Роберт К. Мартин в МЕТОД ШАБЛОНА И СТРАТЕГИЯ: Наследование или Делегирование

Таким образом, шаблон STRATEGY обеспечивает одно дополнительное преимущество над ТЕМПЛАТНЫЙ МЕТОД. В то время как шаблон метода TEMPLATE METHOD позволяет универсальный алгоритм для управления многими возможными подробными реализаций, полностью согласуясь с DIP шаблоном STRATEGY дополнительно позволяет обрабатывать каждую детальную реализацию посредством много разных общих алгоритмов.

DIP - это принцип инверсии зависимостей:

а. Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций. B. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

(Wikipedia и Мартин снова).

Ответ 11

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

 /**
 *  enables replaceable steps in algorithm
 */
public interface HouseStrategy{
      void buildWalls();
      void buildPillars();
}


public class HouseContext{


    //public API that enforces order of execution
    public void build(HouseStrategy strategy){
        buildFoundation();//default implementation
        strategy.buildPillars();//delegated to concrete strategy
        strategy.buildWalls();//delegated to concrete strategy
        buildWindows();//default implementation
    }

    //default implementation
    private void buildWindows() {
        System.out.println("Building Glass Windows");
    }
    //default implementation
    private void buildFoundation() {
        System.out.println("Building foundation with cement,iron rods and sand");
    }

}

public class WoodenHouse implements HouseStrategy {

    @Override
    public void buildWalls() {
        System.out.println("Building Wooden Walls");
    }

    @Override
    public void buildPillars() {
        System.out.println("Building Pillars with Wood coating");
    }

}

public class GlassHouse implements HouseStrategy {

    @Override
    public void buildWalls() {
        System.out.println("Building Wooden Of glass");
    }

    @Override
    public void buildPillars() {
        System.out.println("Building Pillars with glass coating");
    }

}

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

public class GlassHouse implements HouseStrategy,EarthquakeResistantHouseStrategy{......}

Использование

HouseContext context = new HouseContext();

    WoodenHouse woodenHouseStrategy = new WoodenHouse();
    context.build(woodenHouseStrategy);

    GlassHouse glassHouseStrategy = new GlassHouse();
    context.build(glassHouseStrategy);

Один недостаток, который я вижу здесь, состоит в том, что конкретные стратегии могут только изменить вариант поведения алгоритма, то есть buildWalls() и buildPillars(). Если нам нужно изменить инвариантные части, то есть buildFoundation() и buildWindows(), нам нужно сделать другой класс Context, реализующий новое поведение. Тем не менее, мы получаем некоторую возможность повторного использования кода, которая не найдена в чистом шаблоне стратегии: -)