Практическое приложение для понимания режима стратегии

Java

Введение

  В прошлой статье мы узнали о применении шаблона фабрики, а в этой статье мы узнаем о применении шаблона стратегии в реальных проектах.

   Прежде всего, прежде чем говорить о модели стратегии, давайте взглянем на стратегию членства в крупных супермаркетах в повседневной жизни:
  Торговые центры часто формулируют различные стратегии ценообразования продуктов в зависимости от разных клиентов, например, скидка 9 % для обычных участников, скидка 20 % для VIP-членов и скидка 50 % для суперпользователей...

   Теперь мы собираемся создать модуль управления котировками.Краткий момент заключается в том, чтобы предоставить разные скидки для разных клиентов-участников.

   Наш общий код может выглядеть так:

package com.MyMineBug.demoRun.strategy;

import java.math.BigDecimal;

public class MemberManagement {

	public BigDecimal calculatePrice(String customType){
        if ("普通会员用户".equals(customType)) {
            System.out.println("抱歉!普通会员用户打9折!");
            return new BigDecimal("90");
        }else if ("VIP会员".equals(customType)) {
            System.out.println("恭喜你!VIP会员打8折!");
            return new BigDecimal("80");
        }else if("超级会员用户".equals(customType)){
            System.out.println("恭喜你!超级会员用户打5折!");
            return new BigDecimal("50");
        }
        //普通用户都是原价
        return new BigDecimal("100");
    }

}

После тестирования приведенный выше код работает нормально, но приведенный выше код вызывает проблемы. Проблемы с вышеперечисленным:Алгоритмы котировок от разных клиентов размещены в одном методе, что делает метод очень большим(Сейчас это просто демо, так что пока не выглядит раздутым).

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

Принцип открытия-закрытия:

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

2. Закрыт для модификации. При расширении поведения модуля нет необходимости изменять исходный код или двоичный код модуля.

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

Во-вторых, предварительное понимание режима стратегии

2.1 Определения

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

2.2 Структура

1. Роль интерфейса стратегии IStrategy: используется для ограничения ряда конкретных алгоритмов стратегии, роль контекста стратегии StrategyContext использует этот интерфейс стратегии для вызова алгоритма, реализованного конкретной стратегией.

2. Роль реализации конкретной стратегии ConcreteStrategy: реализация конкретной стратегии, то есть реализация конкретного алгоритма.

3. Роль контекста стратегии StrategyContext: Контекст стратегии, отвечающий за взаимодействие с конкретными стратегиями. Обычно объект контекста стратегии содержит реальный объект реализации стратегии, а контекст стратегии может также позволять конкретным реализациям стратегии получать от него соответствующие данные и вызывать обратно методы объекта контекста стратегии.

2.3 Переписать модуль управления котировками, используя паттерн стратегии

   Реализовано здесь, мы внедряем класс реализации нашей стратегии в карту через аннотацию Spring. Когда проект начнется, класс реализации IStrategy будет автоматически внедрен в контекст стратегии StrategyContext. Конкретная реализация выглядит следующим образом:

Интерфейс стратегии публичного котирования:

package com.MyMineBug.demoRun.strategy;

import java.math.BigDecimal;

public interface IStrategy  {

	/**
	 * 计算价格
	 * @return
	 */
	public BigDecimal calculatePrice();
}

Реализация стратегии котирования обычных пользователей:

package com.MyMineBug.demoRun.strategy;

import java.math.BigDecimal;

import org.springframework.stereotype.Component;
@Component("GeneralMember")
public class GeneralMember implements IStrategy{

	@Override
	public BigDecimal calculatePrice() {
		return new BigDecimal("90");
	}

}

Реализация пользовательской политики VIP-члена:

package com.MyMineBug.demoRun.strategy;

import java.math.BigDecimal;

import org.springframework.stereotype.Component;

@Component("VipMember")
public class VipMember implements IStrategy{

	@Override
	public BigDecimal calculatePrice() {
		return new BigDecimal("80");
	}

}

Реализация пользовательской стратегии суперчлена:

package com.MyMineBug.demoRun.strategy;

import java.math.BigDecimal;

import org.springframework.stereotype.Component;

@Component("SuperMember")
public class SuperMember implements IStrategy{

	@Override
	public BigDecimal calculatePrice() {
		return new BigDecimal("50");
	}

}

Контекст цитаты стратегии:

package com.MyMineBug.demoRun.strategy;
/**
 * 策略管理器
 * @author 18360
 *
 */

import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

@Component
public class StrategyContext {
	
	private final Map<String, IStrategy> strategyMap = new ConcurrentHashMap<String, IStrategy>();
	
	/**
	 * 注入所有实现了IStrategy接口的Bean
	 * @param strategyMap
	 */
	@Autowired
	public void StrategyInterface(Map<String, IStrategy> strategyMap) {
		this.strategyMap.clear();
		strategyMap.forEach((k, v)-> this.strategyMap.put(k, v));
	}
	
    /**
     * 计算价格
     * @param memberLevel   会员等级
     * @return              价格
     */
    public BigDecimal calculatePrice(String memberLevel) {
    	if(!StringUtils.isEmpty(memberLevel)){
    		return strategyMap.get(memberLevel).calculatePrice();
    	}
		return null;
    }
}

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

package com.MyMineBug.demoRun.controller;

import java.math.BigDecimal;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.MyMineBug.demoRun.strategy.StrategyContext;

@RestController
@RequestMapping
public class StrategyController {

	@Autowired
	private StrategyContext strategyContext;

	@RequestMapping("/calculatePrice")
	public BigDecimal calculatePrice(@RequestParam("memberLevel") String memberLevel) {
		return strategyContext.calculatePrice(memberLevel);
	}
	
	@RequestMapping("/whello")
	public String hello() {
		return "hello run"; 
	}

}

Если вы запускаете проект весенней загрузки и сообщаете об ошибке, вам необходимо добавить аннотацию сканирования к записи запуска: @ComponentScan(basePackages = {"com.MyMineBug.demoRun"})

После запуска сервиса введите в интерфейсе http://localhost:8080/calculatePrice?memberLevel=GeneralMember

вывод:

3. Глубокое понимание режима стратегии

3.1 Роль шаблона стратегии

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

3.2 В центре внимания шаблона стратегии

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

В нашем первом примере управления котировками мы обнаружили, что каждая реализация алгоритма стратегии соответствует оператору if else в методе calculatePrice в MemberManagement. Мы знаем, что код в операторе if else if можно сказать с точки зрения возможности выполнения. равно, вы выполняете либо if, либо else, либо else if.
Шаблон стратегии    заключается в абстрагировании и инкапсуляции каждой равнозначной конкретной реализации в независимый класс алгоритма, а затем взаимодействии с конкретным классом алгоритма через контекст. Все алгоритмы стратегии равны и имеют одинаковый статус, именно благодаря равенству каждого алгоритма они взаимозаменяемы. Хотя мы можем динамически переключаться между стратегиями, одновременно можно использовать только одну стратегию.

В-четвертых, применение шаблона стратегии в JDK

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

corePoolSize: количество основных потоков в пуле потоков, даже если у этих потоков нет задач, они не будут уничтожены.

maxPoolSize: максимальное количество потоков, которое может быть создано в пуле потоков.

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

unit: единица измерения времени keepAliveTime.

workQueue: до того, как потоки в пуле потоков успеют выполнить задачу, очередь для сохранения задач (когда у потоков в пуле потоков есть задачи для выполнения, все еще есть задачи, которые постоянно отправляются, и эти задачи хранятся в очередь workQueue. середина).

threadFactory: фабрика, которая создает потоки в пуле потоков.

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

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

Интерфейс публичной политики:

Этот интерфейс стратегии имеет четыре класса реализации:

AbortPolicy: политика заключается в том, чтобы напрямую отклонить отправленную задачу и создать исключение RejectedExecutionException.

DiscardPolicy: эта политика также отменяет задачу (ничего не делает для отправленной задачи, несмотря ни на что), но не генерирует исключение.

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

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

Класс ThreadPoolExecutor содержит ссылку на интерфейс RejectedExecutionHandler, чтобы внешний клиент мог самостоятельно сформулировать и внедрить определенные стратегии в конструкторе. Взгляните на его диаграмму классов ниже:

V. Резюме

Преимущества паттерна стратегии:

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

2. Ряд алгоритмов в режиме стратегии взаимозаменяемы и равны. Вместе написана организационная структура if-else. Если в реализации алгоритма есть условные операторы, он представляет собой несколько условных операторов. Режим стратегии можно использовать, чтобы избежать таких несколько условных операторов.

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

Недостатки шаблона стратегии:

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

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

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

Суть паттерна стратегии   :Разделите алгоритм, выберите реализацию.

  Если вы считаете, что это хорошо, пожалуйста, поставьте палец вверх! ! !

  Share Technology And Love Life