Приклад реального світу шаблону стратегії


95

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

Я збирався спробувати пояснити це декільком людям, але єдиним прикладом, який я можу придумати, є використання різних класів перевірки на основі статусу "замовлення".

Я прочитав кілька статей в Інтернеті, але вони зазвичай не описують справжню причину використання стратегії, наприклад, створення звітів / рахунків / перевірку тощо ...

Чи є в реальному світі приклади, коли, на вашу думку, шаблон стратегії є загальним?

Відповіді:


100

Як що до цього:

Ви повинні зашифрувати файл.

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

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

Це можуть бути дві різні стратегії для одного завдання.

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

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



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

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

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

}

The

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

Поверне правильний екземпляр стратегії для шифру.

Я сподіваюся, що це допомагає.

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


8
Ваш приклад - це не більше заводський шаблон? Також я думаю, що це не буде працювати в C #, наприклад. Ваш метод "getCipher ()" є статичним методом, але в C # ви не можете визначити статичний метод на інтерфейсі (ні в Java, я думаю, але щодо цього я не впевнений).
FrenchData

10
Вони йдуть разом. Фабрика створює стратегію, але стратегія сама тримає алгоритм для виконання (в основному) тієї самої операції. Стратегію також можна змінити під час виконання. Щодо заводського методу ви правильно, я його змінюю.
OscarRyz

Для додавання точки Osacars, без заводу це можна створити без заводу Cipher C =null; if (file.size() <= 2048) { C = new InMemoryCipherStrategy(); } else { c= SwaptToDiskCipher (); }
Абхіджіт Мазумдер

Погодьтеся з @FrenchData. Хоча це чудовий приклад, присутність CipherFactoryможе заплутати тих, хто не знайомий зі зразком стратегії.
user487772

1
Фабричний шаблон - це творчість, Стратегія - поведінкова. Є трохи інше, так?
nhoxbypass

62

Знову ж, стара публікація, але все одно з’являється під час пошуку, тому я додаю ще два приклади (код на C #) Мені дуже подобається шаблон Стратегії, оскільки він багато разів рятував мене, коли керівники проектів кажуть: "Ми хочемо, щоб програма робила" X ", але" X "ще не зрозуміла, і вона може змінитися найближчим часом. " Це відео, що пояснює схему стратегії , використовує StarCraft як приклад.

Речі, які потрапляють до цієї категорії:

  • Сортування: Ми хочемо відсортувати ці цифри, але не знаємо, чи будемо використовувати BrickSort, BubbleSort чи інше сортування

  • Перевірка: нам потрібно перевірити елементи відповідно до "Деякого правила", але поки не ясно, яким буде це правило, і ми можемо подумати про нові.

  • Ігри: Ми хочемо, щоб гравець ходив або бігав, коли рухається, але, можливо, в майбутньому він також повинен вміти плавати, літати, телепортуватися, закопуватися під землю тощо.

  • Зберігання інформації: Ми хочемо, щоб програма зберігала інформацію в Базі даних, але пізніше може знадобитися можливість зберегти файл або зробити веб-дзвінок

  • Виведення: нам потрібно вивести X як звичайний рядок, але пізніше це може бути CSV, XML, JSON тощо.


Приклади

У мене є проект, за яким користувачі можуть призначати продукти людям у базі даних. Це присвоєння товару особі має статус "Затверджено" або "Відхилено", що залежить від деяких ділових правил. Наприклад: якщо користувач призначає продукт людині з певним віком, його статус слід відхилити; Якщо різниця між двома полями в елементі перевищує 50, його статус зменшується тощо.

Зараз, на момент розвитку, ці бізнес-правила ще не повністю зрозумілі, і нові правила можуть з’явитися в будь-який час. Потужність страгетного шаблону полягає в тому, що я створив 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, де він використовує шаблон стратегії в частині програми Unit-test

Він створює веб-сайт, який має сторінку, на якій відображаються елементи, засновані на популярності. Однак "Популярним" може бути багато речей (більшість переглядів, більшість підписників, дата створення, найбільша активність, найменша кількість коментарів тощо), і у випадку, якщо керівництво ще не знає, як саме замовити, і може захотіти поекспериментувати з різними замовлення пізніше. Ви створюєте інтерфейс (IOrderAlgorithm або щось інше) з методом замовлення, і дозволяєте об'єкту Orderer делегувати порядок конкретній реалізації інтерфейсу IOrderAlgorithm. Ви можете створити "CommentOrderer", "ActivityOrderer" тощо ... І просто вимкнути їх, коли з'являться нові вимоги.


Я знаю, що це трохи поза сферою питання, але що буде далі? У нас це InternRuleзараз, але як ми спрацьовуємо OvertimeRule? Як ми можемо забезпечити, щоб будь-яка логіка, що називається OvertimeRule.IsApprovedзараз, також викликала InternRule.IsApproved?
Спенсер Рупорт

13

Основні примітки:

  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

Корисні статті:

шаблон стратегії за зонами

шаблон стратегії за джерелом


12

Я можу придумати кілька досить простих прикладів:

  • Сортування списку. Стратегія - це порівняння, за допомогою якого визначається, який із двох пунктів у списку "Перший"
  • Можливо, у вас є програма, де сам алгоритм сортування (QuickSort, HeapSort тощо) може бути обраний під час виконання
  • Appenders, Макети і фільтри в Log4Net і Log4j
  • Менеджери макетів в наборах інтерфейсу користувача
  • Стиснення даних. У вас може бути інтерфейс ICompressor, єдиний метод якого виглядає приблизно так:

    байт [] стиснення (байт [] введення);

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


9

Одним із поширених застосувань шаблону стратегії є визначення власних стратегій сортування (на мовах без функцій вищого порядку), наприклад, сортування списку рядків за довжиною в Java, передача анонімного внутрішнього класу (реалізація інтерфейсу стратегії):

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

Подібним чином стратегії можуть бути використані для власних запитів з об'єктними базами даних, наприклад у db4o:

List<Document> set = db.query(new Predicate<Document>() {
  public boolean match(Document candidate) {
    return candidate.getSource().contains(source);
  }
});

8

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

Для цієї синхронізації я використовую композиційний шаблон стратегії. Основна програма в основному вибирає головну стратегію залежно від дня тижня (синхронізація змінюється / синхронізує всі) та часу семестру щодо академічного календаря. Якщо платіжний цикл закінчується, він також складає його зі стратегією виставлення рахунків. Потім вона запускає обрану стратегію через стандартний інтерфейс.

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


Це дуже хороший приклад. Крім того, це чітко говорить вам про різницю між командою та шаблоном стратегії в двох словах - намір. "Основна програма в основному вибирає головну стратегію залежно від дня тижня"
Уцав Т.

7

Я знаю, що це старе запитання, але, думаю, у мене є ще один цікавий приклад, який я впровадив нещодавно.

Це дуже практичний приклад шаблону стратегії, який використовується в системі доставки документів.

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

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

Щоб вирішити проблему, я створив базовий клас доставки, який містить логіку доставки, а також методи відкочування матеріалів із усіх сховищ. Ці методи фактично не викликаються системою доставки безпосередньо у випадку помилок. Натомість клас використовує ін’єкцію залежності для отримання класу "Стратегія відкоту / обробки помилок" (на основі замовника, що використовує систему), який викликається у разі помилок, що, в свою чергу, викликає методи відкоту, якщо це підходить для цієї стратегії.

Клас доставки сам повідомляє про те, що відбувається з класом стратегії (які документи були доставлені до яких сховищ і які помилки траплялися), і щоразу, коли виникає помилка, він запитує стратегію, продовжувати чи ні. Якщо в стратегії сказано "зупиніть", клас викликає метод "cleanUp" стратегії, який використовує інформацію, повідомлену раніше, щоб вирішити, які методи відкату викликати з класу доставки, або просто нічого не робити.

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

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

Отже, у мене є дві різні стратегії: одна - це QuitterStrategy(яка закриває першу помилку і нічого не очищає), а друга - MaximizeDeliveryToAStrategy(яка намагається якомога більше не переривати процес і ніколи не відмовляти речі, що доставляються в пам’ять A, але відкат речі з Bдоставки доC не вдається).

Наскільки я розумію, це один із прикладів стратегії. Якщо ви (так, читаєте) вважаєте, що я помиляюся, будь ласка, коментуйте нижче та повідомте мене. Мені цікаво, що може означати "чисте" використання шаблону стратегії, і які аспекти моєї реалізації порушують це визначення. Я думаю, це виглядає трохи смішно, тому що стратегічний інтерфейс трохи жирний. У всіх прикладах, які я бачив до цього часу, використовується лише один метод, але я все ще думаю, що це інкапсулює алгоритм (якщо частину бізнес-логіки можна вважати алгоритмом, що, на мою думку, є).

Оскільки стратегія також повідомляється про події під час виконання доставки, її також можна вважати спостерігачем , але це вже інша історія.

З невеликого дослідження, здається, що це "складений шаблон" (наприклад, MVC, шаблон, який використовує декілька шаблонів дизайну внизу певним чином), який називається Advisor . Це радник щодо продовження доставки чи ні, але це також активний обробник помилок, оскільки він може відмовляти речі, коли про це просять.

У будь-якому випадку, це досить складний приклад, який може викликати у вас відчуття, що звичаї стратегії є надто простими / безглуздими. Він може бути справді складним і навіть більш застосовним, якщо його використовувати разом з іншими візерунками.


6

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

Дозвольте пояснити на простому практичному прикладі

enum Speed {
  SLOW, MEDIUM, FAST;
}

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

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

}

interface SortStrategy {

    public void sort(int[] input);
}

class SlowBubbleSortStrategy implements SortStrategy {

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

 }

class MediumInsertationSortStrategy implements SortStrategy {

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

 }

}

class FastQuickSortStrategy implements SortStrategy {

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

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

}  

Тестовий код для цього є

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

}

Той самий приклад взято з http://coder2design.com/strategy-pattern/


Різне використання шаблону стратегії: Перевірки: Коли у вашому коді багато перевірок, їх потрібно зробити. Різні алгоритми: Особливо, коли можуть бути використані різні алгоритми сортування, наприклад, сортування за допомогою бульбашок або швидке сортування. Зберігання інформації: коли ми можемо отримувати інформацію в різних місцях, наприклад, в базі даних або файловій системі. Розбір: під час синтаксичного аналізу ми можемо використовувати різні стратегії для різних входів. Стратегії фільтрування. Стратегії макетування.
Jatinder Pal

5

Хорошим прикладом шаблону стратегії може бути гра, де ми можемо мати різних персонажів, і кожен персонаж може мати кілька зброй для атаки, але одночасно може використовувати лише одну зброю. Отже, ми маємо характер як контекст, наприклад Король, Командор, Лицар, Солдат та зброя як стратегія, де атака () може бути методом / алгоритмом, який залежить від використовуваної зброї. Отже, якби конкретні класи зброї були Sword, Axe, Crossbow, BowAndArrow і т. Д., Всі вони реалізовували б метод attack (). Я впевнений, що додаткові пояснення не потрібні.


1
Я думав, що прийнята відповідь мала говорити про цей приклад :)
Жанкарло Фонталво

2

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

По суті, що ми зробили, ми розбили проблему на дві стратегії, перша - це пошук даних, оскільки ми знали, що у нас є кілька джерел наших віджетів, і нам потрібно було мати можливість отримати дані та перетворити їх на загальну структуру.

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

Сам наш сервіс був дуже важливим: він, по суті, визначав вхідні дані, результати та виконував певну нормалізацію даних, а також використовував шаблон постачальника для підключення постачальників даних, що належать до додатків, та постачальників алгоритмів, які використовували стратегію. Це була досить ефективна система.

У нас були деякі дебати, якщо ми використовували стратегію чи шаблон, який ми ніколи не вирішували.


2

Ви впевнені, що статус "наказу" не є державним зразком? Я здогадуюсь, що замовлення не буде оброблятися по-різному залежно від його статусу.

Візьмемо для прикладу метод Доставка на замовлення:

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

Найкращий приклад державного зразка (та інших зразків), який я знайшов, був у книзі " Шаблони дизайну головним чином ", що дивно. Близькою секундою стане серія блогів Девіда Кампса .


2

Скажімо, ви хочете написати алгоритм для обчислення n-го дня Xday даного місяця та року, наприклад, другого понеділка жовтня 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
public class StrategyDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

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

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

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

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

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

class CreditCardStrategy implements PaymentStrategy {

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

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

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

}

class PaypalStrategy implements PaymentStrategy {

    private String emailId;
    private String password;

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

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

}

class Item {

    private String upcCode;
    private int price;

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

    public String getUpcCode() {
        return upcCode;
    }

    public int getPrice() {
        return price;
    }

}

class ShoppingCart {

    // List of items
    List<Item> items;

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

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

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

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

    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}

1

Кілька тижнів тому я додав загальний інтерфейс Java, який був реалізований одним із наших об'єктів домену. Цей об’єкт домену було завантажено з бази даних, і подання бази даних було зірковою схемою з приблизно 10+ гілками. Одним із наслідків наявності такого важкого об’єкта домену є те, що нам довелося створити інші об’єкти домену, що представляли ту саму схему, хоча і менш важку. Тож я змусив інші легкі об’єкти реалізувати той самий інтерфейс. Інакше кажучи:

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

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

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


1

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

Процес написання даних тоді був досить простим, продовжуйте вискакувати вгорі черги пріоритетів, а потім вибирайте стратегію, засновану на типі об’єкта, який ви видобуваєте.


0

З вікіпедії

У комп'ютерному програмуванні шаблон стратегії (також відомий як шаблон політики) - це поведінковий шаблон дизайну програмного забезпечення, що дозволяє вибирати алгоритм під час виконання. Замість того, щоб безпосередньо реалізовувати один алгоритм, код отримує інструкції під час виконання, які в сімействі алгоритмів використовувати

У програмі Windows Paint ви можете побачити шаблон стратегії, де ви можете самостійно вибрати форму та колір у різних розділах. Тут форма та колір - це алгоритми, які можуть змінюватися під час роботи.

Якщо ви хочете намалювати коло червоним кольором, замість того, щоб вибрати опцію "RedCircle", вони дозволять вам вибрати коло та колір на ваш вибір.

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

Без стратегії шаблон збільшить кількість занять з декартовим продуктом форми та кольору. Також інтерфейс змінюється для кожної реалізації.


0

Уявіть собі гру-шутер із, наприклад, ворогами ШІ. Ви хочете, щоб вони постійно боролися різними способами залежно від того, що відбувається .. За допомогою шаблону стратегії ви можете постійно циклічно та динамічно змінювати спосіб виконання певної дії або дії.

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

public AiShooter{

    FightingStrategy fightingStrategy;

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

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

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

public static void main(){

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

    ... you kill one
    list.get(n).changeStrategy(new Dead());
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.