Пример шаблона стратегии из реального мира

95

Я читал о принципале OCP и о том, как использовать шаблон стратегии для этого.

Я собирался попытаться объяснить это нескольким людям, но единственный пример, который я могу придумать, - это использование разных классов валидации в зависимости от того, в каком статусе находится «заказ».

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

Есть ли какие-нибудь примеры из реального мира, где, по вашему мнению, распространен шаблон стратегии?

Равиндра бабу
источник

Ответы:

100

Как насчет этого:

Вам нужно зашифровать файл.

Для небольших файлов вы можете использовать стратегию «в памяти», когда весь файл читается и сохраняется в памяти (скажем, для файлов размером <1 ГБ).

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

Это могут быть две разные стратегии для одной и той же задачи.

Клиентский код будет выглядеть так же:

 File file = getFile();
 Cipher c = CipherFactory.getCipher( file.size() );
 c.performAction();



// implementations:
interface  Cipher  {
     public void performAction();
}

class InMemoryCipherStrategy implements Cipher { 
         public void performAction() {
             // load in byte[] ....
         }
}

class SwaptToDiskCipher implements Cipher { 
         public void performAction() {
             // swapt partial results to file.
         }

}

В

     Cipher c = CipherFactory.getCipher( file.size() );

Вернул бы правильный экземпляр стратегии для шифра.

Надеюсь, это поможет.

(Я даже не знаю, правильное ли слово Cipher: P)

OscarRyz
источник
8
Ваш пример больше не является фабричным шаблоном? Также я думаю, что это не будет работать, например, на C #. Ваш метод getCipher () является статическим, но в C # вы не можете определить статический метод в интерфейсе (я думаю, и в Java, но в этом я не уверен).
FrenchData
10
Они идут вместе. Фабрика создает стратегию, но сама стратегия содержит алгоритм для выполнения (в основном) той же операции. Стратегию также можно изменить во время выполнения. Насчет заводского метода вы правы, я его поменял.
OscarRyz
Чтобы добавить точку Osacars, без фабрики ее можно создать без фабрики Cipher C =null; if (file.size() <= 2048) { C = new InMemoryCipherStrategy(); } else { c= SwaptToDiskCipher (); }
Абхиджит Мазумдер
Согласитесь с @FrenchData. Являясь отличным примером, присутствие CipherFactoryможет смутить тех, кто не знаком с шаблоном Стратегия.
user487772
1
Фабричный паттерн - о творчестве, Стратегия - о поведенческом. Есть немного другое, правда?
nhoxbypass 08
62

Опять же, старый пост, но все еще появляется при поиске, поэтому я добавлю еще два примера (код на C #). Мне очень нравится шаблон «Стратегия», поскольку он много раз спасал меня, когда менеджеры проектов говорили: «Мы хотим, чтобы приложение выполняло« X », но« X »еще не ясно, и это может измениться в ближайшем будущем. " В этом видео, объясняющем схему стратегии , в качестве примера используется StarCraft.

Материалы, относящиеся к этой категории:

  • Сортировка: мы хотим отсортировать эти числа, но не знаем, будем ли мы использовать BrickSort, BubbleSort или другую сортировку.

  • Проверка: нам нужно проверять элементы в соответствии с «некоторым правилом», но еще не ясно, каким будет это правило, и мы можем подумать о новых.

  • Игры: мы хотим, чтобы игрок либо шел, либо бежал, когда он двигается, но, возможно, в будущем он также сможет плавать, летать, телепортироваться, копаться под землей и т. Д.

  • Хранение информации: мы хотим, чтобы приложение сохраняло информацию в базе данных, но позже ему может потребоваться сохранить файл или сделать веб-вызов

  • Вывод: нам нужно вывести X в виде простой строки, но позже это может быть CSV, XML, JSON и т. Д.


Примеры

У меня есть проект, в котором пользователи могут назначать продукты людям в базе данных. Это назначение продукта человеку имеет статус «Утверждено» или «Отклонено», что зависит от некоторых бизнес-правил. Например: если пользователь назначает продукт человеку определенного возраста, его статус должен быть отклонен; Если разница между двумя полями в элементе больше 50, его статус отклоняется и т. Д.

Сейчас, на момент разработки, эти бизнес-правила еще не полностью ясны, и в любой момент могут появиться новые правила. Сила шаблона stragety в том, что я создал RuleAgent, которому дан список IRules.

public interface IRule {
    bool IsApproved(Assignment assignment); 
 }

В момент назначения продукта человеку я создаю RuleAgent, даю ему список правил (все они реализуют IRule) и прошу его подтвердить назначение. Он будет проходить по всем своим правилам. Поскольку все они реализуют один и тот же интерфейс, у всех естьIsApproved метод и возвращают false, если какой-либо из них возвращает false.

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

public OvertimeRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Timesheet >= 40)
        {
            return false;
        }
        return true;
    }
}

public InternRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Title == "Intern")
        {
            return false;
        }
        return true;
    }
}

Вы видите, что вам не нужно постоянно добавлять или удалять операторы if или код, просто создайте новый класс правил, реализующий интерфейс IRUle, и при необходимости отключите их.


Другой замечательный пример: серия видео Скотта Аллена на http://www.asp.net/mvc/pluralsight, где он использует шаблон стратегии в части приложения, посвященной модульному тестированию.

Он создает веб-сайт, на котором отображаются элементы в зависимости от их популярности. Однако «популярным» может быть множество вещей (большинство просмотров, большинство подписчиков, дата создания, наибольшая активность, наименьшее количество комментариев и т. Д.), И в случае, если руководство еще не знает, как сделать заказ, и может захотеть поэкспериментировать с разными заказы на более поздний срок. Вы создаете интерфейс (IOrderAlgorithm или что-то в этом роде) с помощью метода заказа и позволяете объекту Orderer делегировать упорядочивание конкретной реализации интерфейса IOrderAlgorithm. Вы можете создать "CommentOrderer", "ActivityOrderer" и т. Д. И просто отключить их, когда появятся новые требования.

Серил Уилтинк
источник
Я знаю, что это немного выходит за рамки вопроса, но что будет дальше? У нас есть это InternRuleсейчас, но как мы запускаем OvertimeRule? Как мы убедимся , что независимо логики под названием OvertimeRule.IsApprovedтеперь звонки InternRule.IsApproved?
Спенсер Рупорт 03
14

Основные примечания:

  1. Стратегия - это шаблон поведенческого проектирования. Он используется для переключения между семейством алгоритмов.

  2. Этот шаблон содержит один абстрактный интерфейс стратегии и множество конкретных реализаций стратегии ( алгоритмов ) этого интерфейса.

  3. Приложение использует только интерфейс стратегии . В зависимости от некоторого параметра конфигурации конкретная стратегия будет привязана к интерфейсу .

Схема UML из википедии

введите описание изображения здесь

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

Взгляните на простой пример. Этот пример можно распространить на онлайн-приложения для розничной торговли, которые легко предоставляют скидки на товары в корзине в особые дни / счастливые часы.

import java.util.*;

/* Interface for Strategy */
interface OfferStrategy {
    public String getName();
    public double getDiscountPercentage();
}
/* Concrete implementation of base Strategy */
class NoDiscountStrategy implements OfferStrategy{
    public String getName(){
        return this.getClass().getName();
    }
    public double getDiscountPercentage(){
        return 0;
    }
}
/* Concrete implementation of base Strategy */
class QuarterDiscountStrategy implements OfferStrategy{
    public String getName(){
        return this.getClass().getName();
    }
    public double getDiscountPercentage(){
        return 0.25;
    }
}
/* Context is optional. But if it is present, it acts as single point of contact
   for client. 

   Multiple uses of Context
   1. It can populate data to execute an operation of strategy
   2. It can take independent decision on Strategy creation. 
   3. In absence of Context, client should be aware of concrete strategies. Context acts a wrapper and hides internals
   4. Code re-factoring will become easy
*/
class StrategyContext {
    double price; // price for some item or air ticket etc.
    Map<String,OfferStrategy> strategyContext = new HashMap<String,OfferStrategy>();
    StrategyContext(double price){
        this.price= price;
        strategyContext.put(NoDiscountStrategy.class.getName(),new NoDiscountStrategy());
        strategyContext.put(QuarterDiscountStrategy.class.getName(),new QuarterDiscountStrategy());        
    }
    public void applyStrategy(OfferStrategy strategy){
        /* 
        Currently applyStrategy has simple implementation. You can use Context for populating some more information,
        which is required to call a particular operation            
        */
        System.out.println("Price before offer :"+price);
        double finalPrice = price - (price*strategy.getDiscountPercentage());
        System.out.println("Price after offer:"+finalPrice);
    }
    public OfferStrategy getStrategy(int monthNo){
        /*
            In absence of this Context method, client has to import relevant concrete Strategies everywhere.
            Context acts as single point of contact for the Client to get relevant Strategy
        */
        if ( monthNo < 6 )  {
            return strategyContext.get(NoDiscountStrategy.class.getName());
        }else{
            return strategyContext.get(QuarterDiscountStrategy.class.getName());
        }

    }
}
public class StrategyDemo{    
    public static void main(String args[]){
        StrategyContext context = new StrategyContext(100);
        System.out.println("Enter month number between 1 and 12");
        int month = Integer.parseInt(args[0]);
        System.out.println("Month ="+month);
        OfferStrategy strategy = context.getStrategy(month);
        context.applyStrategy(strategy);
    }

}

вывод:

Enter month number between 1 and 12
Month =1
Price before offer :100.0
Price after offer:100.0

Enter month number between 1 and 12
Month =7
Price before offer :100.0
Price after offer:75.0

Полезные статьи:

стратегияшаблон от dzone

шаблон стратегии по источникам

Равиндра бабу
источник
спасибо .... имеет смысл .... согласен, applyStrategy () - это чудовище, способное достичь большого количества черной магии. Также нестатический способ удержания стратегий в strategyContext на высшем уровне
Арнаб Датта,
12

Я могу вспомнить несколько довольно простых примеров:

  • Сортировка списка. Стратегия - это сравнение, используемое для определения того, какой из двух элементов в списке является «первым».
  • У вас может быть приложение, в котором сам алгоритм сортировки (QuickSort, HeapSort и т. Д.) Может быть выбран во время выполнения.
  • Приложения, макеты и фильтры в Log4Net и Log4j
  • Диспетчеры компоновки в инструментах пользовательского интерфейса
  • Сжатие данных. У вас может быть интерфейс ICompressor, единственный метод которого выглядит примерно так:

    byte [] compress (byte [] вход);

    Ваши конкретные классы сжатия могут быть такими как RunLengthCompression, DeflateCompression и т. Д.

Эрик Поль
источник
9

Одним из распространенных способов использования шаблона стратегии является определение пользовательских стратегий сортировки (на языках без функций высшего порядка), например, для сортировки списка строк по длине в Java, передавая анонимный внутренний класс (реализация интерфейса стратегии):

List<String> names = Arrays.asList("Anne", "Joe", "Harry");
Collections.sort(names, new Comparator<String>() {
  public int compare(String o1, String o2) {
    return o1.length() - o2.length();
  }
});
Assert.assertEquals(Arrays.asList("Joe", "Anne", "Harry"), names);

Аналогичным образом стратегии можно использовать для собственных запросов к объектным базам данных, например, в db4o:

List<Document> set = db.query(new Predicate<Document>() {
  public boolean match(Document candidate) {
    return candidate.getSource().contains(source);
  }
});
Фабиан Штег
источник
8

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

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

Не знаю, насколько это распространено, но мне показалось, что это идеально подходит для шаблона стратегии.

tvanfosson
источник
Это очень хороший пример. Кроме того, он ясно показывает разницу между шаблоном команды и стратегии в двух словах - намерение. «Основная программа в основном выбирает основную стратегию в зависимости от дня недели»
Утсав Т.
7

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

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

У меня была система доставки PDF, которая получила архив, содержащий множество документов и некоторые метаданные. Основываясь на метаданных, он решил, куда поместить документ; скажем, в зависимости от данных, я мог бы хранить документ в A, BилиC системах хранения данных, или смесь из трех.

Эту систему использовали разные клиенты, и у них были разные требования к откату / обработке ошибок в случае ошибок: один хотел, чтобы система доставки останавливалась при первой ошибке, оставляла все документы уже доставленными в их хранилища, но останавливала процесс и не доставляла ничего больше ; другой хотел, чтобы он откатился Bв случае ошибок при сохранении C, но оставил то, что уже было доставлено A. Несложно представить, что у третьего или четвертого тоже будут другие потребности.

Чтобы решить эту проблему, я создал базовый класс доставки, который содержит логику доставки, а также методы отката данных со всех хранилищ. Эти методы фактически не вызываются системой доставки напрямую в случае ошибок. Вместо этого класс использует внедрение зависимостей для получения класса «Стратегия отката / обработки ошибок» (на основе клиента, использующего систему), который вызывается в случае ошибок, который, в свою очередь, вызывает методы отката, если это подходит для этой стратегии.

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

rollbackStrategy.reportSuccessA(...);
rollbackStrategy.reportFailureB(...);

if (rollbackStrategy.mustAbort()) {
    rollbackStrategy.rollback(); // rollback whatever is needed based on reports
    return false;
}

Итак, у меня теперь есть две разные стратегии: одна QuitterStrategy(которая завершает работу при первой ошибке и ничего не очищает), а другая - MaximizeDeliveryToAStrategy(которая пытается как можно больше не прерывать процесс и никогда не откатывать данные, доставленные в хранилище A, но откатывает вещи из Bif доставки в Cнеудачную).

Насколько я понимаю, это один из примеров паттерна стратегии. Если вы (да, читаете) думаете, что я ошибаюсь, оставьте комментарий ниже и дайте мне знать. Мне любопытно, что можно считать «чистым» использованием шаблона стратегии, и какие аспекты моей реализации нарушают определение. Я думаю, это выглядит немного забавно, потому что интерфейс стратегии немного толстоват. Во всех примерах, которые я видел до сих пор, используется только один метод, но я все же считаю, что он инкапсулирует алгоритм (если часть бизнес-логики может считаться алгоритмом, что, как мне кажется, так и есть).

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

После небольшого исследования кажется, что это "составной шаблон" (например, MVC, шаблон, который использует несколько шаблонов проектирования определенным образом), называемый Советчиком . Это советник относительно того, должна ли доставка продолжаться или нет, но это также активный обработчик ошибок, поскольку он может откатить данные, когда их попросят.

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

Gui Prá
источник
6

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

Позвольте мне объяснить на простом практическом примере

enum Speed {
  SLOW, MEDIUM, FAST;
}

class Sorter {
 public void sort(int[] input, Speed speed) {
    SortStrategy strategy = null;
    switch (speed) {
    case SLOW:
        strategy = new SlowBubbleSortStrategy();
        break;
    case MEDIUM:
        strategy = new MediumInsertationSortStrategy();
        break;

    case FAST:
        strategy = new FastQuickSortStrategy();
        break;
    default:
        strategy = new MediumInsertationSortStrategy();
    }
    strategy.sort(input);
 }

}

interface SortStrategy {

    public void sort(int[] input);
}

class SlowBubbleSortStrategy implements SortStrategy {

   public void sort(int[] input) {
    for (int i = 0; i < input.length; i++) {
        for (int j = i + 1; j < input.length; j++) {
            if (input[i] > input[j]) {
                int tmp = input[i];
                input[i] = input[j];
                input[j] = tmp;
            }
        }
    }
    System.out.println("Slow sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
  }

 }

class MediumInsertationSortStrategy implements SortStrategy {

public void sort(int[] input) {
    for (int i = 0; i < input.length - 1; i++) {
        int k = i + 1;
        int nxtVal = input[k];
        while (input[k - 1] > nxtVal) {
            input[k] = input[k - 1];
            k--;
            if (k == 0)
                break;
        }
        input[k] = nxtVal;
    }
    System.out.println("Medium sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }

 }

}

class FastQuickSortStrategy implements SortStrategy {

public void sort(int[] input) {
    sort(input, 0, input.length-1);
    System.out.println("Fast sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
}

private void sort(int[] input, int startIndx, int endIndx) {
    int endIndexOrig = endIndx;
    int startIndexOrig = startIndx;
    if( startIndx >= endIndx)
        return;
    int pavitVal = input[endIndx];
    while (startIndx <= endIndx) {
        while (input[startIndx] < pavitVal)
            startIndx++;
        while (input[endIndx] > pavitVal)
            endIndx--;
        if( startIndx <= endIndx){
            int tmp = input[startIndx];
            input[startIndx] = input[endIndx];
            input[endIndx] = tmp;
            startIndx++;
            endIndx--;
        }
    }
    sort(input, startIndexOrig, endIndx);
    sort(input, startIndx, endIndexOrig);
 }

}  

Тестовый код для этого:

public class StrategyPattern {
  public static void main(String[] args) {
    Sorter sorter = new Sorter();
    int[] input = new int[] {7,1,23,22,22,11,0,21,1,2,334,45,6,11,2};
    System.out.print("Input is : ");
    for (int i : input) {
        System.out.print(i + ",");
    }
    System.out.println();
    sorter.sort(input, Speed.SLOW);
 }

}

Тот же пример взят из http://coder2design.com/strategy-pattern/

Джатиндер Пал
источник
Различные варианты использования шаблона стратегии: Валидации: Когда в вашем коде необходимо выполнить множество проверок. Различные алгоритмы: особенно когда могут использоваться разные алгоритмы сортировки, например пузырьковая или быстрая сортировка. Хранение информации: когда мы можем разместить информацию в разных местах, например, в базе данных или файловой системе. Парсинг: во время синтаксического анализа мы можем использовать разные стратегии для разных входов. Стратегии фильтрации. Макетные стратегии.
Jatinder Pal 08
5

Хорошим примером шаблона стратегии может быть игра, в которой у нас могут быть разные персонажи, и каждый персонаж может иметь несколько видов оружия для атаки, но одновременно может использовать только одно оружие. Итак, у нас есть персонаж в качестве контекста, например Король, Командир, Рыцарь, Солдат и оружие в качестве стратегии, где атака () может быть методом / алгоритмом, который зависит от используемого оружия. Итак, если бы конкретными классами оружия были Sword, Axe, Crossbow, BowAndArrow и т. Д., Все они реализовали бы метод attack (). Я уверен, что дальнейшие объяснения не нужны.

Сандипан Кармакар
источник
1
Я думал, что принятый ответ должен был говорить об этом примере :)
Жанкарло Фонтальво
2

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

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

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

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

У нас были споры о том, используем ли мы стратегию или шаблонный шаблон, которые мы так и не нашли.

Джош Берке
источник
2

Вы уверены, что статус «заказа» не является шаблоном состояния? У меня есть подозрение, что заказ не будет обрабатываться по-разному в зависимости от его статуса.

Возьмем, к примеру, метод Доставка по заказу:

order.Ship();
  • Если способ доставки зависит от статуса, то у вас есть шаблон стратегии.
  • Однако, если метод Ship () завершается успешно только после того, как заказ был оплачен, а заказ еще не отправлен, у вас есть шаблон состояния.

Лучший пример паттерна состояний (и других паттернов), который я нашел, был в книге « Head First Design Patterns », которая потрясающая. На втором месте будет серия шаблонов ведения блога Дэвида Кампса .

Grootjans
источник
2

Допустим, вы хотите написать алгоритм для вычисления n-го X- дня данного месяца и года, например, второго понедельника октября 2014 года. Вы хотите использовать класс Android Time android.text.format.Timeдля представления даты, но вы также хотите написать общий алгоритм это также может относиться к java.util.Calendar.

Вот что я сделал.

В DatetimeMath.java:

public interface DatetimeMath { 
    public Object createDatetime(int year, int month, int day);

    public int getDayOfWeek(Object datetime);

    public void increment(Object datetime);
}

В TimeMath.java:

public class TimeMath implements DatetimeMath {
    @Override
    public Object createDatetime(int year, int month, int day) {
        Time t = new Time();
        t.set(day, month, year);
        t.normalize(false);
        return t;
    }

    @Override
    public int getDayOfWeek(Object o) {
        Time t = (Time)o;
        return t.weekDay;
    }   

    @Override
    public void increment(Object o) {
        Time t = (Time)o;
        t.set(t.monthDay + 1, t.month, t.year);
        t.normalize(false);
    }
}

В OrdinalDayOfWeekCalculator.java класс с универсальным алгоритмом:

public class OrdinalDayOfWeekCalculator {   
    private DatetimeMath datetimeMath;

    public OrdinalDayOfWeekCalculator(DatetimeMath m) {
        datetimeMath = m;
    }

    public Object getDate(int year, int month, int dayOfWeek, int ordinal) {
        Object datetime = datetimeMath.createDatetime(year, month, 1);
        if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
            return datetime;
        } 
        int xDayCount = 0;
        while (xDayCount != ordinal) {
            datetimeMath.increment(datetime);
            if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
                xDayCount++;
            }
        }
        return datetime;
    }
}

В моем приложении для Android я бы назвал что-то вроде

OrdinalDayOfWeekCalculator odowc = 
        new OrdinalDayOfWeekCalculator(new TimeMath());
Time canadianThanksgiving = (Time)odowc.getDate(
        year, Calendar.OCTOBER, Time.MONDAY, 2);

Если я хочу повторно использовать тот же алгоритм для java.util.Calendar, я бы просто написал класс CalendarMath, который реализует три метода в DatetimeMath, а затем использовал бы

OrdinalDayOfWeekCalculator odowc2 = 
        new OrdinalDayOfWeekCalculator(new CalendarMath());
Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate(
        year, Calendar.OCTOBER, Calendar.MONDAY, 2);
аномальный
источник
2
public class StrategyDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        Item item1 = new Item("1234", 10);
        Item item2 = new Item("5678", 40);

        cart.addItem(item1);
        cart.addItem(item2);

        // pay by paypal
        cart.pay(new PaypalStrategy("myemail@example.com", "mypwd"));

        // pay by credit card
        cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"));
    }
}

interface PaymentStrategy {
    public void pay(int amount);
}

class CreditCardStrategy implements PaymentStrategy {

    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;

    public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate) {
        this.name = nm;
        this.cardNumber = ccNum;
        this.cvv = cvv;
        this.dateOfExpiry = expiryDate;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid with credit/debit card");
    }

}

class PaypalStrategy implements PaymentStrategy {

    private String emailId;
    private String password;

    public PaypalStrategy(String email, String pwd) {
        this.emailId = email;
        this.password = pwd;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid using Paypal.");
    }

}

class Item {

    private String upcCode;
    private int price;

    public Item(String upc, int cost) {
        this.upcCode = upc;
        this.price = cost;
    }

    public String getUpcCode() {
        return upcCode;
    }

    public int getPrice() {
        return price;
    }

}

class ShoppingCart {

    // List of items
    List<Item> items;

    public ShoppingCart() {
        this.items = new ArrayList<Item>();
    }

    public void addItem(Item item) {
        this.items.add(item);
    }

    public void removeItem(Item item) {
        this.items.remove(item);
    }

    public int calculateTotal() {
        int sum = 0;
        for (Item item : items) {
            sum += item.getPrice();
        }
        return sum;
    }

    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}
Вивек Гоэль
источник
1

Несколько недель назад я добавил общий интерфейс Java, который был реализован одним из наших доменных объектов. Этот объект домена был загружен из базы данных, и представление базы данных было звездообразной схемой с примерно 10+ ветвями. Одним из последствий наличия такого тяжелого объекта домена является то, что нам пришлось создать другие объекты домена, которые представляли ту же схему, хотя и менее тяжелые. Поэтому я заставил другие легкие объекты реализовать тот же интерфейс. Иначе говоря, у нас было:

public interface CollectibleElephant { 
    long getId();
    String getName();
    long getTagId();
}

public class Elephant implements CollectibleElephant { ... }
public class BabyElephant implements CollectibleElephant { ... }

Изначально я хотел использовать CollectibleElephantдля сортировки Elephants. Довольно быстро мои товарищи по команде начали CollectibleElephantвыполнять проверки безопасности, фильтровать их по мере их отправки в графический интерфейс и т. Д.

Алан
источник
1

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

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

Coxy
источник
0

Из википедии

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

В приложении Windows Paint вы можете увидеть шаблон стратегии, в котором вы можете независимо выбирать форму и цвет в разных разделах. Здесь форма и цвет - это алгоритмы, которые можно изменять во время выполнения.

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

Shape redCircle = new RedCircle(); // Without stretegy Pattern
Shaped redCircle = new Shape("red","circle"); // With Strategy pattern

Без стратегии шаблон увеличит количество классов с декартовым произведением формы и цвета. Также интерфейс меняется для каждой реализации.

бхаранитхарана
источник
0

Представьте, например, шутер с противниками ИИ. Вы хотите, чтобы они постоянно сражались по-разному, в зависимости от того, что происходит ... С помощью шаблона стратегии вы можете непрерывно зацикливаться и динамически изменять способ выполнения определенного действия.

interface FightingStategy{
    public void fight();
}
public Defense implements FightingStrategy{
    public void figth(){
        ... hide behind wall to shoot
    }
}
public Berserker implements FightingStrategy{
    public void fight(){
        ... run towards you, headrolls and shoots
    }
}
public Dead implements FightingStrategy{
    public void fight(){
        ... is dead, doesn't move
    }
}

public AiShooter{

    FightingStrategy fightingStrategy;

    public AiShooter(){
        fightStrategy = new Berserker();
    }

    public void fight(){
        this.fightingStrategy.fight();
    }

    public void changeStrategy(FightingStrategy f){
        this.fightingStrategy = f;
    }
}

public static void main(){

    ... create list of AiShooters...
    while (condition){
        list.forEach(shooter -> shooter.fight());
    }
    ... you shoot back
    list.ForEach(shooter -> shooter.changeStrategy(new 
Defense()));

    ... you kill one
    list.get(n).changeStrategy(new Dead());
}
Седрик С
источник