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

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

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

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

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

16.12.2008 01:29:29
16 ОТВЕТОВ

Что насчет этого:

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

Для небольших файлов вы можете использовать стратегию «в памяти», когда весь файл читается и хранится в памяти (скажем, для файлов <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)

98
11.01.2010 15:56:02
Не является ли ваш пример более фабричным шаблоном? Также я думаю, что это не будет работать в C # например. Ваш метод "getCipher ()" является статическим методом, но в C # вы не можете определить статический метод на интерфейсе (ни в Java, я думаю, но в этом я не уверен).
FrenchData 9.01.2010 17:20:05
Они идут вместе. Фабрика создает стратегию, но сама стратегия содержит алгоритм для выполнения (в основном) одной и той же операции. Стратегия также может быть изменена во время выполнения. По поводу заводского метода вы правы, я должен это изменить.
OscarRyz 11.01.2010 15:55:10
Чтобы добавить точку Осакара, без фабрики это может быть создано без фабрики Cipher C =null; if (file.size() <= 2048) { C = new InMemoryCipherStrategy(); } else { c= SwaptToDiskCipher (); }
Abhijit Mazumder 15.06.2014 19:58:24
Согласитесь с @FrenchData. Будучи отличным примером, присутствие CipherFactoryможет сбить с толку тех, кто не знаком с паттерном стратегии.
user487772 30.04.2015 08:17:56
Фабричная модель - это творчество, стратегия - это поведение. Есть немного другое право?
nhoxbypass 8.01.2018 18:14:51

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

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

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

8
16.12.2008 02:36:25
Это очень хороший пример. Кроме того, он четко говорит вам разницу между командным и стратегическим паттерном в двух словах - намерение. «Основная программа в основном выбирает мастер-стратегию в зависимости от дня недели»
Utsav T 8.07.2018 17:02:45

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

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

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

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

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

2
16.12.2008 03:57:39

Несколько недель назад я добавил общий интерфейс 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
16.12.2008 05:06:26

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

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

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

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

2
22.01.2009 23:07:35

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

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

1
29.01.2009 02:06:50

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

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

    byte [] compress (byte [] input);

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

12
8.01.2010 21:07:26

Одним из распространенных примеров использования шаблона стратегии является определение пользовательских стратегий сортировки (в языках без функций высшего порядка), например, для сортировки списка строк по длине в 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);
  }
});
9
11.01.2010 16:12:32

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

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

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

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

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

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

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

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

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

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

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

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

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

7
5.10.2012 06:25:55

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

Вещи, которые попадают в эту категорию:

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

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

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

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

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


Примеры

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

Сейчас, на момент разработки, эти бизнес-правила еще не полностью ясны, и в любое время могут появиться новые правила. Сила stragety-pattern заключается в том, что я создал 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» и т. Д. И просто отключить их при появлении новых требований.

57
12.07.2018 22:26:40
Я знаю, что это немного выходит за рамки вопроса, но что будет дальше? У нас есть это InternRuleсейчас, но как мы запускаем OvertimeRule? Как мы можем гарантировать, что любая логика, вызываемая OvertimeRule.IsApprovedсейчас, также вызывает InternRule.IsApproved?
Spencer Ruport 3.03.2019 15:08:17

Допустим, вы хотите написать алгоритм для вычисления n-го X дня данного месяца и года, например, второй понедельник октября 2014 года. Вы хотите использовать класс времени Android 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
18.01.2014 19:27:08

Хорошим примером паттерна стратегии может служить игра, в которой у нас могут быть разные персонажи, и каждый персонаж может иметь несколько видов оружия для атаки, но одновременно может использовать только одно оружие. Таким образом, у нас есть персонаж в качестве контекста, например King, Commander, Knight, Soldier и оружие в качестве стратегии, где attack () может быть методом / алгоритмом, который зависит от используемого оружия. Так что, если бы конкретными классами оружия были Sword, Axe, Crossbow, BowAndArrow и т. Д., То все они реализовали бы метод attack (). Я уверен, что дальнейшие объяснения не нужны.

5
15.01.2015 16:08:20
Я думал, что принятый ответ должен был говорить об этом примере :)
Jeancarlo Fontalvo 12.11.2016 21:59:12

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

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

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/

6
8.07.2015 11:38:23
Различное использование шаблона стратегии: Валидации. Когда в вашем коде необходимо выполнить много проверок. Различные алгоритмы: особенно, когда могут использоваться разные алгоритмы сортировки, например, пузырьковая сортировка или быстрая сортировка. Хранение информации: когда мы можем предоставлять информацию в разных местах, например, в базе данных или файловой системе. Разбор: при разборе мы можем использовать разные стратегии для разных входов. Стратегии фильтрации. Стратегии размещения.
Jatinder Pal 8.07.2015 13:02:18

Ключевые примечания:

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

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

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

UML Diagram из Википедии

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

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

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

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

шаблон стратегии при создании источников

12
16.10.2017 16:52:48
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
23.05.2017 04:38:06

Из википедии

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

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

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

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

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

0
8.06.2018 05:30:36