Обратите внимание на общедоступную учетную запись «Java back-end technology full stack» и ответьте «000», чтобы получить много электронных книг.
Эта статья является третьей в серии статей о шаблонах проектирования:
То, чем я делюсь с вами сегодня,策略模式, схема конкретного содержания выглядит следующим образом:
жизненный случай
В наш век Интернета, особенно в городе, есть группа людей, которые ездят на аккумуляторных велосипедах, шаттлах по улицам и переулкам, эта группа людей является курьером.
На вынос я тоже заказал немало. Однажды, когда я разместил заказ на вынос, я вдруг подумал о шаблоне проектирования ---режим стратегии.
Какова схема стратегии?
策略模式: Английский этоStrategy Pattern, что означает, что семейства алгоритмов определяются и инкапсулируются отдельно, чтобы их можно было заменять друг другом.Этот шаблон проектирования позволяет изменениям в алгоритме не влиять на пользователей, использующих алгоритм.
английский
Define a family of algorithms,encapsulate each one,and make them interchangeable.
Грубое значение: определите набор алгоритмов, инкапсулируйте каждый алгоритм и сделайте их взаимозаменяемыми.
В шаблоне стратегии поведение класса или его алгоритма может быть изменено во время выполнения. Этот тип шаблона проектирования относится к行为型模式.
Общий код паттерна стратегии
Java-код реализован следующим образом:
class Client {
//抽象策略类 Strategy
interface IStrategy {
void algorithm();
}
//具体策略类 ConcreteStrategy
static class ConcreteStrategyA implements IStrategy {
@Override
public void algorithm() {
System.out.println("Strategy A");
}
}
//具体策略类 ConcreteStrategy
static class ConcreteStrategyB implements IStrategy {
@Override
public void algorithm() {
System.out.println("Strategy B");
}
}
//上下文环境
static class Context {
private IStrategy mStrategy;
public Context(IStrategy strategy) {
this.mStrategy = strategy;
}
public void algorithm() {
this.mStrategy.algorithm();
}
}
public static void main(String[] args) {
//选择一个具体策略
IStrategy strategy = new ConcreteStrategyA();
//来一个上下文环境
Context context = new Context(strategy);
//客户端直接让上下文环境执行算法
context.algorithm();
}
}
Из приведенного выше общего кода мы можем узнать его UML-диаграмму.
UML-диаграмма шаблона стратегии
Роли в режиме стратегии
Из диаграммы классов UML видно, что шаблон стратегии в основном включает три роли:
-
контекстные роли (
Context): Контекстная среда, используемая для работы со стратегией, защищает прямой доступ модуля высокого уровня (клиента) к стратегии и алгоритму и инкапсулирует возможные изменения; -
Роль абстрактной политики (
Strategy): определяет поведение политики или алгоритма; -
конкретные стратегические роли (
ConcreteStrategy): реализация конкретной стратегии или алгоритма;
Преимущества и недостатки режима стратегии
преимущество
-
Паттерн стратегии соответствует принципу «открыто-закрыто».
-
Избегайте использования нескольких операторов преобразования, таких как:
if...else,switchутверждение. -
Использование режима стратегии может повысить конфиденциальность и безопасность алгоритма.
недостаток
-
Клиент должен знать все политики и решать, какую из них использовать
-
В коде много классов политик, что увеличивает сложность постобслуживания.
Сценарии использования шаблона стратегии
В ежедневной разработке шаблон стратегии подходит для следующих трех сценариев:
-
Для одного и того же типа проблемы существует несколько методов обработки, каждый из которых может решить проблему независимо.
-
Алгоритмы должны свободно переключаться между сценариями.
-
Сценарии, требующие маскировки правил алгоритма
Это все еще не совсем понятно.
Далее мы будем использовать жизненные случаи для его реализации, чтобы все знали, как используется шаблон стратегии.
Рефакторинг кода платежного кейса, три версии
При оформлении заказа на улице и выборе способа оплаты, думаю, эту функцию можно реализовать, имитируя режим стратегии. Далее реализуем через три варианта итерации, что очень интересно.
первое издание
Сначала определите абстрактный класс Pay:
//定义抽象类,我们可以把一些共用功能放在抽象类里实现
//比如:可用余额和本次支付金额进行比较,统一返回“支付失败”
public abstract class Pay {
abstract void doPay();
}
Ниже моделируются три способа оплаты:
public class AliPay extends Pay {
@Override
public void doPay() {
System.out.println("使用支付宝支付");
}
}
public class UnionPay extends Pay {
@Override
public void doPay() {
System.out.println("使用银联支付");
}
}
public class WechatPay extends Pay {
@Override
public void doPay() {
System.out.println("使用微信支付");
}
}
Произведем оплату еще раз:
public class PayTest {
public static void main(String[] args) {
//把选择权交给了用户
Order order = new Order(new WechatPay());
order.pay();*
}
}
результат операции:
使用微信支付
Таким образом, мы используем режим стратегии для реализации простой версии оплаты, но есть очень неудобное место, то есть нам приходится каждый раз вручную создавать новый объект метода оплаты. В связи с этим мы провели рефакторинг первого издания.
второе издание
Предыдущая реализация осталась прежней, меняется только то, что при инициации платежа нужно передать ключ только с фронтенда, реализация следующая:
public class PayTest {
public static void main(String[] args) {
String payKey = "Wechat";
Order order = null;
//通过判断前端传过来的key,判断使用哪种支付方式
if (payKey.equals("Ali")) {
order = new Order(new AliPay());
} else if (payKey.equals("Wechat")) {
order = new Order(new WechatPay());
} else if (payKey.equals("union")) {
order = new Order(new UnionPay());
}else {
//给出一个默认方式
order = new Order(new WechatPay());
}
order.pay();
}
}
результат операции
使用微信支付
Таким образом, мы поняли, что через ключ, переданный от внешнего интерфейса, а затем выберите соответствующий способ оплаты. Но снова возникает вопрос: если количество способов оплаты будет продолжать расти, не будет ли их все больше и больше, если...иначе? Не увеличиваются ли затраты на последующее обслуживание?
Итак, есть третье издание.
Третье издание
Во второй редакции будет много if...else, что принесет неудобства в последующем сопровождении кода, поэтому в этой редакции мы его рефакторим и вводим зарегистрированный паттерн singleton.
import java.util.HashMap;
import java.util.Map;
public enum PayStrategyEnum {
ALI_PAY("Ali"),
WECHAT_PAY("Wechat"),
UNION_PAY("union"),
//默认使用微信支付
DEFAULT_PAY("Wechat");
private String key;
PayStrategyEnum(String key) {
this.key = key;
}
private static final Map<String, Pay> payKeyMap = new HashMap();
static {
payKeyMap.put(ALI_PAY.key, new AliPay());
payKeyMap.put(WECHAT_PAY.key, new WechatPay());
payKeyMap.put(UNION_PAY.key, new UnionPay());
payKeyMap.put(DEFAULT_PAY.key, new WechatPay());
}
public static Pay getPay(String payKey) {
if (!payKeyMap.containsKey(payKey)) {
return payKeyMap.get(DEFAULT_PAY.key);
}
return payKeyMap.get(payKey);
}
}
Затем, когда заказ оплачен, он становится таким:
public class PayTest {
public static void main(String[] args) {
String payKey = "Wechat";
Order order = new Order(PayStrategyEnum.getPay(payKey));
order.pay();
}
}
результат операции
使用微信支付
Таким образом, мы успешно избежали многих if...else, круто!
На самом деле, три приведенные выше версии кода кажутся очень крутыми?В этом сила шаблона проектирования.
PS: Касательно вышеперечисленных трех версий, на самом деле, мы можем продолжать улучшать и рефакторить.Если вам интересно, вы можете попробовать, как продолжить рефакторинг.
Суммировать
Что ж, вот и все о сегодняшнем режиме стратегии. На самом деле в большинстве случаев шаблоны проектирования не существуют сами по себе, а используются в сочетании нескольких шаблонов проектирования.
Шаблон стратегии использует объектно-ориентированный механизм наследования и полиморфизма, так что одно и то же поведение может быть реализовано по-разному в разных сценариях.
Самый запоминающийся случай:
Мы можем использовать различные виды транспорта, чтобы добраться до Пекина.
На самолете, по скоростной железной дороге, на машине, на машине, на велосипеде. Есть много способов, вы можете выбрать тот, который вы хотите.
Наконец, резюмируйте шаблон стратегии в одном предложении:
Все дороги ведут в Рим
Что ж, сегодняшний режим стратегии представлен здесь.
Ждем ваших лайков и ретвитов.