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

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

На выходных мне было нечего делать.Я смотрела "8 сезон Игры Престолов" дома.Я смотрела его с большим интересом.Хотя он показался мне немного незавершенным,я не могла не посмотреть,кто сможет сесть на Железный трон.

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

Стратегия

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

Например, такие предложения мы видим на площадках для выноса. Полная скидка, членство и красные конверты и т. д. Каждая крупная скидка включает в себя несколько льготных планов. Например, в событии полного сокращения у вас может быть 20 минус 15, 50 минус 30 и т. д. одновременно. Члены включают обычных членов, суперчленов и т. д.

Множественные преференциальные схемы в рамках каждого преференциального метода на самом деле являются стратегией. Эти стратегии взаимоисключающие и взаимозаменяемые. И есть определенный порядок приоритетов.

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

Как рассчитать сумму

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

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

Код можно написать так:

public BigDecimal calPrice(BigDecimal orderPrice, String buyerType) {

    if (BuyerType.SUPER_VIP.name().equals(buyerType)) {
        return orderPrice.multiply(new BigDecimal(0.8));
    }

    if (BuyerType.VIP.name().equals(buyerType)) {
        return orderPrice.multiply(new BigDecimal(0.9));
    }

    return orderPrice;
}

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

Добавить другой тип членства

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

public BigDecimal calPrice(BigDecimal orderPrice, String buyerType) {

    if (BuyerType.PARTICULARLY_VIP.name().equals(buyerType)) {
        return orderPrice.multiply(new BigDecimal(0.7));
    }

    if (BuyerType.SUPER_VIP.name().equals(buyerType)) {
        return orderPrice.multiply(new BigDecimal(0.8));
    }

    if (BuyerType.VIP.name().equals(buyerType)) {
        return orderPrice.multiply(new BigDecimal(0.9));
    }

    return orderPrice;
}

Изменения скидок для участников

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

public BigDecimal calPrice(BigDecimal orderPrice, String buyerType) {

    if (BuyerType.PARTICULARLY_VIP.name().equals(buyerType)) {
        if (orderPrice.compareTo(new BigDecimal(30)) > 0) {
            return orderPrice.multiply(new BigDecimal(0.7));
        }
    }

    if (BuyerType.SUPER_VIP.name().equals(buyerType)) {
        return orderPrice.multiply(new BigDecimal(0.8));
    }

    if (BuyerType.VIP.name().equals(buyerType)) {
        return orderPrice.multiply(new BigDecimal(0.9));
    }

    return orderPrice;
}

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

public BigDecimal calPrice(BigDecimal orderPrice, String buyerType) {

    if (BuyerType.PARTICULARLY_VIP.name().equals(buyerType)) {
        if (orderPrice.compareTo(new BigDecimal(30)) > 0) {
            return orderPrice.multiply(new BigDecimal(0.7));
        }
    }

    if (BuyerType.SUPER_VIP.name().equals(buyerType)) {
        return orderPrice.multiply(new BigDecimal(0.8));
    }

    if (BuyerType.VIP.name().equals(buyerType)) {
        int  superVipExpiredDays  = getSuperVipExpiredDays();
        int superVipLeadDiscountTimes  = getSuperVipLeadDiscountTimes();
        if(superVipExpiredDays < 7 && superVipLeadDiscountTimes =0){
            updateSuperVipLeadDiscountTimes();
            return orderPrice.multiply(new BigDecimal(0.8));
        }
        return orderPrice.multiply(new BigDecimal(0.9));
    }

    return orderPrice;
}


Зачем использовать шаблон стратегии

Приведенные выше коды, все коды скидок для участников написаны в методе calPrice.Чтобы увеличить или уменьшить тип участника, вам нужно изменить весь метод. Также учитывайте приоритет этой скидки членства.

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

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

Например, я только что изменил скидку для суперчленов со скидки 20% на скидку 15. В настоящее время, поскольку коды все вместе, необходимо вернуть все функции скидки члена, когда она выходит в сеть.

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

режим стратегии

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

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

В частности, шаблон стратегии подходит только для управления группой алгоритмов одного типа, и эти алгоритмы полностью исключают друг друга. То есть в любой момент времени может действовать только одна из множества стратегий. Например, при полной скидке между 10 минус 20 и 20 минус 30; между скидкой обычного члена и скидкой суперчлена и т. д.

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

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

Основные роли реализации шаблона стратегии следующие:

абстрактный класс стратегии

Сначала определите интерфейс, этот интерфейс является абстрактным классом стратегии, интерфейс определяет метод расчета цены, а конкретный метод реализации определяется конкретным классом стратегии.

public interface Buyer {

    /**
     * 计算应付价格
     */
    public BigDecimal calPrice(BigDecimal orderPrice);
}

конкретный класс стратегии

Для разных членов определены три конкретных класса политики, и каждый класс реализует метод расчета цены.

/**
 * 专属会员
 */
public class ParticularlyVipBuyer implements Buyer {

    @Override
    public BigDecimal calPrice(BigDecimal orderPrice) {
         if (orderPrice.compareTo(new BigDecimal(30)) > 0) {
            return orderPrice.multiply(new BigDecimal(0.7));
        }
    }
}


/**
 * 超级会员
 */
public class SuperVipBuyer implements Buyer {

    @Override
    public BigDecimal calPrice(BigDecimal orderPrice) {
        return orderPrice.multiply(new BigDecimal(0.8));
    }
}


/**
 * 普通会员
 */
public class VipBuyer implements Buyer {

    @Override
    public BigDecimal calPrice(BigDecimal orderPrice) {
        int  superVipExpiredDays  = getSuperVipExpiredDays();
        int superVipLeadDiscountTimes  = getSuperVipLeadDiscountTimes();
        if(superVipExpiredDays < 7 && superVipLeadDiscountTimes =0){

            return orderPrice.multiply(new BigDecimal(0.8));
        }
        return orderPrice.multiply(new BigDecimal(0.9));
    }
}

Определения приведенных выше классов отражают принципы проектирования изменений инкапсуляции. Изменения в конкретных методах скидки для разных элементов не повлияют на другие элементы.

После определения класса абстрактной стратегии и класса конкретной стратегии мы определяем класс контекста, так называемый класс контекста — это класс интегрированного алгоритма. В данном примере это кассовая система. Объединяйте участников комбинированным способом.

public class Cashier {

    /**
     * 会员,策略对象
     */
    private Buyer buyer;

    public Cashier(Buyer buyer){
        buyer = buyer;
    }

    public BigDecimal quote(BigDecimal orderPrice) {
        return this.buyer.calPrice(orderPrice);
    }
}

Этот класс Cashier является классом контекста, определение которого отражаетМногоцелевая комбинация, меньше наследования, программирование интерфейса, а не программирование реализации — два принципа проектирования.

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

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

Давайте определим клиента, чтобы протестировать его:

public class Test {

    public static void main(String[] args) {

        //选择并创建需要使用的策略对象
        Buyer strategy = new VipBuyer();
        //创建上下文
        Cashier cashier = new Cashier(strategy);
        //计算价格
        BigDecimal quote = cashier.quote(300);
        System.out.println("普通会员商品的最终价格为:" + quote.doubleValue());

        strategy = new SuperVipBuyer();
        cashier = new Cashier(strategy);
        quote = cashier.quote(300);
        System.out.println("超级会员商品的最终价格为:" + quote.doubleValue());
    }
}

Выходной результат:

//普通会员商品的最终价格为:270.0
//超级会员商品的最终价格为:240.0

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

Преимущества и недостатки паттерна стратегии

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

Режим стратегии имеет следующие характеристики:

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

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

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

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

Однако серебряной пули в программировании не бывает, и режим стратегии не исключение.У него есть и недостатки.Для начала рассмотрим и подытожим его достоинства:

  • Стратегический режим обеспечивает идеальную поддержку «принципа открытого-закрытого». Пользователи могут выбирать алгоритмы или поведения без изменения исходной системы или гибко добавлять новые алгоритмы или поведения.

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

  • Используйте шаблон стратегии, чтобы избежать множественных условных операторов (if-else). Множественные условные операторы нелегко поддерживать.Он смешивает логику алгоритма или поведения с логикой алгоритма или поведения, перечисленными в множественном условном операторе, который является более примитивным и отсталым, чем метод наследования.

Но в то же время у него есть и следующие недостатки:

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

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


Наконец, прикрепите ментальную карту содержания этой статьи: