намерение
Позволяет объекту изменять свое поведение при изменении его внутреннего состояния
Разговор: позволяет объектам изменять определенные методы привязки, когда они меняют свое состояние.
Рождение государственного образца
[Продукт]: Привет, брат-разработчик, нам нужно разработать娃娃机
, вы можете подумать о том, как его оформить заранее.
【Развитие】: Кукольная машина? Я думаю об этом, ему нужно положить монеты, пользователь перемещается, подтверждает выборку и завершает эти действия. Кажется, это очень легко сделать. Используйте переменную для поддержания ее текущей стадии, а затем напишите четыре оператора if.
[БОСС]: Вы собираетесь использовать один основной метод, четыре подметода с оператором if и переменной состояния?
// 伪代码
public void handle() {
if (flag == A) {
a();
}
if (flag == B) {
b();
}
}
[Разработчик]: Да, босс, вы действительно аскариды в моем животе!
[БОСС]: Аскарид, это большая ошибка! , вы хотите привязать этот же метод к слоту для монет, кнопке и джойстику?
[Разработка]: Да, это должны быть разные методы, выставленные пользователям одновременно, я подумаю об этом еще раз
Основной код HeadFirst
"Определите интерфейс состояния, одновременно инкапсулируйте изменения и используйте ключевое слово по умолчанию для инкапсуляции метода по умолчанию."
public interface State {
/** 投币 **/
default void giveMoney() {
System.out.println("无法投币");
}
/** 移动滑杆 **/
default void move() {
System.out.println("无法移动滑杆");
}
/** 抓取 **/
default void grab() {
System.out.println("无法抓取");
}
void changeState();
}
"Состояние монет Одно из состояний"
public class MoneyState implements State{
Context context;
public MoneyState(Context context) {
this.context = context;
}
@Override
public void giveMoney() {
System.out.println("已投币!");
changeState();
}
@Override
public void changeState() {
context.setExecute(new MoveState(context));
}
}
Чтобы минимизировать код, показано только одно из состояний.Мы видим, что когда класс состояния MoneyState выполняет бизнес-метод, которому он принадлежит, класс состояния, удерживаемый контекстом, изменяется, что приводит к изменению состояния, и контекст становится более ясным, т. е. мне нужно думать только о том, каково мое следующее состояние.
Идея оформления государственного режима:
- Контекстный контекст, состояние удержания
- Интерфейс верхнего уровня состояния
- ConcreteState Конкретное состояние
Проще говоря,
- Необходимо четко понимать, сколько существует различных состояний, и определять его основные методы через интерфейсы для инкапсуляции изменений.
- Класс состояния содержит контекст контекста и меняет свое состояние после обработки основным методом.
❝Если это кажется немного двусмысленным, рекомендуется после прочтения этой статьи посетить проект с открытым исходным кодом тематических шаблонов проектирования, в котором есть конкретные примеры кода, а ссылка находится внизу
❞
Ключ к шаблону состояния
- Определите все возможные состояния и их переходы
- Каждое состояние в шаблоне явного состояния может быть представлено пользователю одновременно.
❝Точно так же, как различные состояния кукольного автомата, вставка монеты, перемещение джойстика, нажатие кнопки подтверждения и т. д. могут не срабатывать последовательно.
❞
Весь паттерн "процесс"
Что, если имя метода одинаково для всех состояний?
В вышеизложенном мы, вероятно, знаем характеристики режима состояния, инкапсулируем состояние в класс и меняем само состояние при вызове метода состояния-ядра.Имена различных методов состояния, рассматриваемых в настоящее время, могут быть разными, предполагая что у всех нас одинаковое имя Как это будет?
Сначала мы столкнемся с проблемой, мы не знаем, сколько раз нужно вызвать метод (потому что могут повторяться случаи A-B), но если цикл бесконечен, контролировать, где он заканчивается, и следует ли продолжить Логотип, кажется, может решить эту проблему.
Приходите на процессный кейс
В двух словах: начните обрабатывать заказы
- Если это нормально, он перейдет в успешное состояние, будет помещен в хранилище и завершит выполнение.
- Если это не удается, войдите в состояние отказа, проверьте, нужно ли выполнять повторно, и измените состояние, чтобы обработать заказ.
код выше
"Контекст контекст"
public class Context {
/**
* 最大执行次数
*/
public static final Integer FAIL_NUM = 3;
/***
* 失败次数
*/
private int failNum;
/**
* 是否继续执行的标识
*/
private boolean isAbandon;
/***
* 当前状态
*/
private StateInterface stateInterface;
public Context() {
this.stateInterface = new HandleOrder();
this.failNum = 1;
this.isAbandon = false;
}
/***
* 处理方法
*/
public void handle () {
stateInterface.doAction(this);
}
// 省略无用代码...
}
"Статус обработки заказа"
public class HandleOrder implements StateInterface {
@Override
public void doAction(Context context) {
printCurrentState();
// do somethings
int num = (int) (Math.random() * 11);
if (num >= 8) {
System.out.println("处理订单完成, 进入成功状态...");
context.setStateInterface(new SuccessOrder());
} else {
System.out.println("处理订单失败, 进入失败状态...");
context.setStateInterface(new FailOrder());
}
CodeUtils.spilt();
}
@Override
public StateEnums getCurrentState() {
return StateEnums.HANDLE_ORDER;
}
}
"метод вызова клиента"
public class App {
public static void main(String[] args) {
// 模拟从队列中取任务按流程循环执行
Context context = new Context();
while (true) {
// 校验是否为废弃 | 已完成任务
if (context.isAbandon()) {
System.out.println("此条任务不再执行... ");
break;
}
context.handle();
}
}
}
Вывод результатов теста:
# 当前状态:订单处理
# 处理订单失败, 进入失败状态...
# ------------------------
# 当前状态:处理订单失败
# 订单处理失败... 当前执行次数: 1
# ------------------------
# 当前状态:订单处理
# 处理订单失败, 进入失败状态...
# ------------------------
# 当前状态:处理订单失败
# 订单处理失败... 当前执行次数: 2
# ------------------------
# 当前状态:订单处理
# 处理订单完成, 进入成功状态...
# ------------------------
# 当前状态:处理订单成功
# 订单处理完成 -> 进入入库逻辑...
# 入库处理完成
# ------------------------
# 此条任务不再执行...
❝Если это кажется немного двусмысленным, рекомендуется после прочтения этой статьи посетить проект с открытым исходным кодом тематических шаблонов проектирования, в котором есть конкретные примеры кода, а ссылка находится внизу
❞
Сценарии для режима "Процесс"
В таком дизайне правильнее сказать, что это не столько изменение состояния, сколько изменение «процесса», поэтому его можно использовать как решение для многих фоновых задач, особенно при столкновении со многими сценариями бизнес-процессов. , что может значительно улучшить ремонтопригодность кода: мне нужно думать только о своем "потоке"
Принципы дизайна, которым нужно следовать
- Изменения инкапсуляции: предоставьте метод по умолчанию в родительском интерфейсе, и подкласс может реализовать соответствующий метод состояния.
- Больше композиции, меньше наследования: шаблон состояния часто противопоставляется шаблону стратегии, оба из которых используют композицию, а не наследование, чтобы расширить свои вариации и возможности.
Какие сценарии подходят для использования режима состояния
- Поведение объекта зависит от его состояния, и он должен изменять свое поведение во время выполнения в зависимости от состояния.
- Операция содержит большой условный оператор с несколькими ответвлениями, и эти ответвления зависят от состояния объекта.
Наконец
"Прикрепите диаграмму UML для шаблона состояния в книге GOF:"
Связанные ссылки на код
- С учетом кейсов в двух классических книгах "HeadFirst" и "GOF"
- Предоставляет дружественное руководство по чтению