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

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

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

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

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

19 ответов

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

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

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

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

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

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" и т. Д. И просто отключить их при появлении новых требований.

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

  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

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

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

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

    byte [] compress (byte [] input);

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

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

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

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

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

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

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

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

У меня была система доставки 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. Это советник о том, должна ли доставка продолжаться или нет, но он также является активным обработчиком ошибок, так как он может откатывать вещи по запросу.

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

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

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

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/

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);
    }
}

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

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

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

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

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

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

We then also realized that we had multiple algorithims some were based on weighting the parameters, others were very weird and propitery and I couldn't do them justice without pulling out visios and charts and well you get the picture, we had lots of algorithims for selecting the best people.

Our service itself was very thing it essentially defined the inputs, outputs and did some normalization of the data, it also used a provider pattern to plug-in the application specific data providers and algorithim providers which used the strategy. This was a fairly effective system.

We had some debates if we were using a strategy or a template pattern which we never resolved.

Пример расчета итогового налога на товары и услуги за товар

      public interface TaxCalculation {

    public Double calculateTax(Double price);  
}
      public class FivePercentage implements TaxCalculation {

    @Override
    public Double calculateTax(Double price) {
        
        Double dbl = (price*5)/100;
        return dbl;
    }

}
      public class EighteenPercentage implements TaxCalculation {

    @Override
    public Double calculateTax(Double price) {
        Double dbl = (price*18)/100;
        return dbl;
    }

}
      public class Item {

    public String name;
    public Double price;
    public int taxRate;
    public Double totalTax;
    
    public Item(String name, Double price, int taxRate) {
        super();
        this.name = name;
        this.price = price;
        this.taxRate = taxRate;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }
    public int getTaxRate() {
        return taxRate;
    }

    public void setTaxRate(int taxRate) {
        this.taxRate = taxRate;
    }

    public Double getTotalTax() {
        return totalTax;
    }

    public void setTotalTax(Double totalTax) {
        this.totalTax = totalTax;
    }

    public void calculateTax(TaxCalculation taxcalulation, Double price) {
        this.totalTax = taxcalulation.calculateTax(price);
    }
    
    @Override
    public String toString() {
        return "Items [name=" + name + ", price=" + price + ", taxRate=" + taxRate + ", totalTax=" + totalTax + "]";
    }
    
}
      public class CalculateTax {

    public static void main(String[] args) {
        
        List<Item> itemList = new ArrayList<>();
        
        Item item1 = new Item("Engine Oil", 320.0, 5);
        Item item2 = new Item("Painting", 3500.00, 18);
        
        itemList.add(item1);
        itemList.add(item2);
        
        itemList.stream().forEach(x-> {
            if(x.getTaxRate() == 5) {
                x.calculateTax(new FivePercentage(), x.getPrice());
            } else if(x.getTaxRate() == 18) {
                x.calculateTax(new EighteenPercentage(), x.getPrice());
            }
        });
        
        itemList.stream().forEach(x-> {
            System.out.println(x.toString());
        });
    }
}

Допустим, вы хотите написать алгоритм для вычисления 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);

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

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

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

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

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

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

Этот ответ предназначен для тех, кто является новичком и хочет понять это на простейшем возможном примере - (Ссылка: Headfirst Design Patterns)

      #include<iostream>
using namespace std;

/*
    Where it is applicable?
    The selection of an algorithm is required from a family of algorithms.
    To avoid multiple conditional statements for selection of algorithms
    and to hide its algorithm data structures and complexity from client.
*/

class Fly {
public:
    virtual void fly() = 0;
};

//concrete Fly : rocketFly
class rocketFly : public Fly {
public:
    void fly() {
        cout <<"rocketFly::fly()" << endl;
    }
};

//concrete Fly : normalFly
class normalFly : public Fly {
public:
    void fly() {
        cout <<"normalFly::fly()" << endl;
    }
};

//Duck "HAS A" relationship with Fly
class Duck {
private:
    //Duck has a Fly behavour
    Fly* flyObj;
public:
    Duck(Fly* obj) : flyObj(obj) {
        
    }

    void DuckFly() {
        flyObj->fly();
    }
};

int main() {
    rocketFly* rObj = new rocketFly;
    Duck wildDuck(rObj);
    wildDuck.DuckFly();

    normalFly* nObj = new normalFly;
    Duck cityDuck(nObj);
    cityDuck.DuckFly();

    /*
        I didn't have to create classes like wildDuck which inherits from Duck and they implement their own
        fly, quack etc behaviour. There will be code duplication.
        So, instead of that, create an interface of fly, make concrete fly classes with different
        fly behaviour. Use objects to any of these concrete classes to inject to one generic duck
        class which will automatically call correct fly behaviour.
    */

return 0;
}

Из википедии

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

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

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

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

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

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

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());
}
Другие вопросы по тегам