Паттерн Состояние
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 98 из 110.
Паттерн Состояние (State pattern) позволяет объекту изменять свое поведение при изменении его внутреннего состояния, создавая впечатление, что объект изменил свой класс. Вместо использования сложных условных операторов для обработки различных состояний, вы инкапсулируете каждое состояние в отдельный класс и делегируете поведение текущему объекту состояния.
Паттерн состоит из Context, который хранит ссылку на текущее состояние, и классов State, которые определяют поведение для каждого возможного состояния. Когда состояние контекста изменяется, его поведение меняется автоматически:
abstract class DocumentState {
void publish(Document doc);
String getStatus();
}
class DraftState implements DocumentState {
@override
void publish(Document doc) {
print('Moving to review...');
doc.setState(ReviewState());
}
@override
String getStatus() => 'Draft';
}
class ReviewState implements DocumentState {
@override
void publish(Document doc) {
print('Document published!');
doc.setState(PublishedState());
}
@override
String getStatus() => 'Under Review';
}
class PublishedState implements DocumentState {
@override
void publish(Document doc) {
print('Already published.');
}
@override
String getStatus() => 'Published';
}
class Document {
DocumentState _state = DraftState();
void setState(DocumentState state) => _state = state;
void publish() => _state.publish(this);
String getStatus() => _state.getStatus();
}
void main() {
var doc = Document();
print(doc.getStatus()); // Draft
doc.publish(); // Moving to review...
print(doc.getStatus()); // Under Review
doc.publish(); // Document published!
print(doc.getStatus()); // Published
}Каждый класс состояния обрабатывает действие publish() по-разному и может переводить документ в следующее состояние. Классу Document не требуются условные операторы для проверки своего текущего состояния — он просто делегирует выполнение тому объекту состояния, который активен в данный момент. Этот паттерн идеально подходит для объектов с четко выраженными режимами поведения, таких как системы обработки заказов, медиаплееры или системы документооборота.
Задание
ЛегкоДавайте создадим систему светофора, используя паттерн Состояние (State)! Вы создадите светофор, который циклически переключается между различными состояниями, где каждое состояние определяет цвет светофора и то, как он переходит в следующее состояние.
Вы организуете свой код в двух файлах:
traffic_light.dart: Этот файл содержит ваши классы состояний и контекст светофора. Создайте абстрактный классTrafficLightStateс двумя методами:String getColor(), который возвращает текущий цвет светофора, иvoid next(TrafficLight light), который переводит светофор в следующее состояние. Реализуйте три конкретных класса состояний:RedState— возвращает'RED'в качестве цвета и выводит'Stop! Light is red.'при вызовеnext(), затем переходит вGreenStateGreenState— возвращает'GREEN'в качестве цвета и выводит'Go! Light is green.'при вызовеnext(), затем переходит вYellowStateYellowState— возвращает'YELLOW'в качестве цвета и выводит'Caution! Light is yellow.'при вызовеnext(), затем переходит вRedState
TrafficLight(контекст), который начинает работу в состоянииRedState. У него должен быть методsetState()для изменения текущего состояния, методgetColor(), который делегирует выполнение текущему состоянию, и методchange(), который вызываетnext()у текущего состояния.main.dart: Импортируйте файл светофора и продемонстрируйте работу паттерна Состояние. Создайте объектTrafficLightи выведите его начальный цвет. Затем вызовитеchange()три раза, выводя цвет после каждого изменения. Это покажет, как светофор проходит через все состояния и возвращается к началу.
Обратите внимание, что классу TrafficLight не нужны никакие условные операторы для определения поведения — каждое состояние знает свой цвет и то, какое состояние следует за ним. Светофор просто делегирует выполнение тому состоянию, которое активно в данный момент!
Ожидаемый вывод:
RED
Stop! Light is red.
GREEN
Go! Light is green.
YELLOW
Caution! Light is yellow.
REDШпаргалка
Паттерн Состояние (State) позволяет объекту изменять свое поведение при изменении его внутреннего состояния. Вместо использования сложных условных операторов каждое состояние инкапсулируется в отдельный класс.
Паттерн состоит из:
- Контекст (Context): Хранит ссылку на текущее состояние
- Классы состояний (State classes): Определяют поведение для каждого возможного состояния
Базовая структура:
abstract class DocumentState {
void publish(Document doc);
String getStatus();
}
class DraftState implements DocumentState {
@override
void publish(Document doc) {
print('Moving to review...');
doc.setState(ReviewState());
}
@override
String getStatus() => 'Draft';
}
class Document {
DocumentState _state = DraftState();
void setState(DocumentState state) => _state = state;
void publish() => _state.publish(this);
String getStatus() => _state.getStatus();
}Контекст делегирует поведение текущему объекту состояния. Каждый класс состояния обрабатывает действия по-разному и может инициировать переход в следующее состояние. Это избавляет от необходимости использовать условные операторы для проверки текущего состояния.
Идеально подходит для объектов с четко выраженными режимами поведения, таких как обработка заказов, медиаплееры или системы документооборота.
Попробуйте сами
import 'traffic_light.dart';
void main() {
// TODO: Создайте экземпляр TrafficLight
// TODO: Выведите начальный цвет
// TODO: Вызовите change() и выведите цвет (3 раза, чтобы пройти через все состояния)
// Первое изменение: RED -> GREEN
// Второе изменение: GREEN -> YELLOW
// Третье изменение: YELLOW -> RED
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыБиблиотеки и импортВведение в ООПКлассы и объектыКлючевое слово thisМетодыПеременные экземпляраОсновы конструкторовИтоги — Простой калькулятор4Null-безопасность
Введение в Null-безопасностьNullable и Non-Nullable типыОператоры ? и !Ключевое слово Late и Null-безопасностьNull-aware операторыNull-безопасность в классахИтоги — Система профилей пользователей7Абстрактные классы и интерфейсы
Абстрактные классыАбстрактные методыИнтерфейсы в DartНеявные интерфейсыРеализация против наследованияМножественные интерфейсыИтоги — Калькулятор фигур10Коллекции и обобщения
Обзор List, Set, MapТипобезопасные коллекцииОбобщенные классыОбобщенные методыОграничения обобщенийIterable и IteratorИтоги: Обобщенное хранилище13Продвинутые концепции ООП
Композиция против наследованияМетоды расширенияВызываемые классыЗапечатанные классы (Dart 3)Записи (Dart 3)Паттерны и сопоставление (3.0)Перечисления с методами16Проект: Управление библиотекой
Обзор проектаКлассы Book и User2Конструкторы в Dart
Конструктор по умолчаниюИменованные конструкторыСписки инициализацииКонстантные конструкторыФабричные конструкторыПеренаправляющие конструкторыИтоги — Shape Builder5Инкапсуляция
Публичные и приватные членыСоглашение о префиксе _Приватность на уровне библиотекГеттеры и сеттеры: подробный разборСкрытие данныхИтоги — Записи о студентах8Mixins
Введение в MixinsСоздание MixinsИспользование нескольких MixinsКлючевое слово on в MixinsMixin и наследованиеMixin и интерфейсИтоги: Система животных11Специальные методы
Переопределение toString()Переопределение hashCode и ==Интерфейс ComparableМетод call()Переопределение noSuchMethodПовторение — Пользовательская коллекция14Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy3Свойства классов
Члены экземпляра и статические членыПоля Final и ConstПеременные LateСтатические методы и поляГеттеры и сеттерыИтоги — Менеджер банковского счета6Наследование
Основы наследованияКлючевое слово superПереопределение методовАннотация @overrideКлючевое слово final для классовКонструкторы и наследованиеИтоги: Иерархия сотрудников9Полиморфизм
Основы полиморфизмаПолиморфизм через интерфейсыПроверка типов во время выполненияОператоры is и asКлючевое слово covariantИтоги — Обработчик платежей12Асинхронное ООП
Futures и async/awaitОсновы StreamsКонтроллеры StreamАсинхронные конструкторыАсинхронность в методах классовИтоги — Data Fetcher15Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий