Реальный мир Пример стратегии

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

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

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

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

Ответ 1

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

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

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

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

Ответ 2

Опять же, старый пост, но он все равно включается в поиск, поэтому я добавлю еще два примера (код на С#). Мне очень нравится шаблон "Стратегия", так как он много раз меня спас, когда руководители проектов говорят: "Мы хотим, чтобы приложение делало" 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" и т.д. И просто отключить их при появлении новых требований.

Ответ 3

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

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

    byte [] compress (byte [] input);

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

Ответ 4

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

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

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

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

Диаграмма UML из Википедии

enter image description here

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

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

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

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

Ответ 5

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

Ответ 6

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

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

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

Ответ 7

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

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

У меня была система доставки 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 завершается с ошибкой).

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

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

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

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

Ответ 8

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

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

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/

Ответ 9

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

Ответ 10

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

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

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

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

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

Ответ 11

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

Возьмем, к примеру, метод Ship on the Order:

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

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

Ответ 12

Скажем, вы хотите написать алгоритм для вычисления nth Xday данного месяца и года, например, второй понедельник октября 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);

Ответ 13

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

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

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

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

Ответ 14

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

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

Ответ 15

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("[email protected]", "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);
    }
}

Ответ 16

Из википедии

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

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

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

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

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