Паттерн Состояние
Часть раздела Object Oriented Programming путешествия по Python на Coddy. Урок 53 из 64.
Паттерн Состояние (State) позволяет объекту изменять свое поведение при изменении его внутреннего состояния. Создается впечатление, что объект изменил свой класс в зависимости от его текущего состояния.
Вот простые классы состояний для светофора:
class RedState:
def next_state(self, light):
print("Red -> Green")
light.state = GreenState()
def current_color(self):
return "Red"
class GreenState:
def next_state(self, light):
print("Green -> Yellow")
light.state = YellowState()
def current_color(self):
return "Green"
class YellowState:
def next_state(self, light):
print("Yellow -> Red")
light.state = RedState()
def current_color(self):
return "Yellow"Каждое состояние определяет, что происходит при переходе в следующее состояние.
Создайте класс контекста, который хранит текущее состояние:
class TrafficLight:
def __init__(self):
self.state = RedState() # Начинаем с красного
def change(self):
self.state.next_state(self)
def get_color(self):
return self.state.current_color()Светофор делегирует поведение своему текущему объекту состояния.
Используйте светофор:
light = TrafficLight()
print(f"Current: {light.get_color()}")
light.change() # Красный -> Зеленый
print(f"Current: {light.get_color()}")
light.change() # Зеленый -> Желтый
print(f"Current: {light.get_color()}")
light.change() # Желтый -> Красный
print(f"Current: {light.get_color()}")Создайте еще один пример с простым плеером:
class PlayingState:
def play(self, player):
print("Already playing")
def stop(self, player):
print("Stopping music")
player.state = StoppedState()
class StoppedState:
def play(self, player):
print("Starting music")
player.state = PlayingState()
def stop(self, player):
print("Already stopped")
class MusicPlayer:
def __init__(self):
self.state = StoppedState()
def play(self):
self.state.play(self)
def stop(self):
self.state.stop(self)
player = MusicPlayer()
player.play() # Запуск музыки
player.play() # Уже воспроизводится
player.stop() # Остановка музыки
player.stop() # Уже остановленоВывод:
Current: Red
Red -> Green
Current: Green
Green -> Yellow
Current: Yellow
Yellow -> Red
Current: Red
Starting music
Already playing
Stopping music
Already stoppedКлючевой момент: Паттерн «Состояние» (State Pattern) инкапсулирует поведение, зависящее от состояния, в отдельные классы и позволяет объекту контекста делегировать выполнение текущему состоянию. При изменении состояния поведение меняется автоматически. Это избавляет от сложных конструкций if/else и упрощает добавление новых состояний.
Задание
ЛегкоВ этом испытании вы реализуете класс State в файле state.py с использованием правильной инкапсуляции и методов. Файл содержит подробные комментарии TODO, которые помогут вам выполнить реализацию шаг за шагом.
Набор тестов разработан для проверки того, что ваша реализация соответствует всем требованиям и правильно обрабатывает исключительные ситуации. Используйте результаты тестов, чтобы понять ожидаемое поведение и доработать свое решение.
Попробуйте сами
from state import State
# Комплексный обработчик тестовых случаев
test_case = input()
if test_case == "basic_test":
obj = State("Test Name")
obj.display_info()
elif test_case == "validation_test":
obj = State("Validation Test")
print(f"Name: {obj.name}")
elif test_case == "empty_name_test":
obj = State("")
obj.display_info()
print(f"Name property: {obj.name}")
elif test_case == "special_chars_test":
obj = State("Test@#$%")
obj.display_info()
print(f"Name property: {obj.name}")
elif test_case == "long_name_test":
long_name = "A" * 100
obj = State(long_name)
obj.display_info()
print(f"Name length: {len(obj.name)}")
elif test_case == "multiple_states_test":
states = [
State("California"),
State("Texas"),
State("New York"),
State("Florida")
]
for state in states:
state.display_info()
print(f"Name via property: {state.name}")
elif test_case == "attribute_access_test":
obj = State("Access Test")
# Прямой доступ к приватному атрибуту (не рекомендуется)
print(f"Direct access (not recommended): {obj._name}")
# Доступ через свойство (рекомендуется)
print(f"Property access (recommended): {obj.name}")
elif test_case == "property_behavior_test":
obj = State("Original Name")
print(f"Original name: {obj.name}")
# Попытка изменить имя (завершится ошибкой, так как сеттер отсутствует)
try:
obj.name = "New Name"
except AttributeError as e:
print(f"Error when trying to modify name: {e}")
# Показать, что имя не изменилось
print(f"Name after modification attempt: {obj.name}")В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыПараметр selfМетодыАтрибутыМетод-конструктор (__init__)Повторение — Простой калькулятор4Наследование
Базовое наследованиеФункция super()Переопределение методовМножественное наследованиеПорядок разрешения методовИтоги — Иерархия сотрудников7Специальные методы
Введение в магические методыПерегрузка операторовМагические методы контейнеровПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy5Полиморфизм
Снова о переопределении методовУтиная типизацияАбстрактные классы и методыПроектирование интерфейсовИтоги — Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияМиксиныСтатические методы и методы классаДекораторы классовМенеджеры контекста11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Свойства классов
Переменные экземпляра и классаДекораторы свойствПриватные атрибутыИтоги — Менеджер банковского счета6Инкапсуляция
Public, Protected, Private члены классаМодификаторы доступаСокрытие данныхДекораторы property: продвинутый уровеньИтоги: Система учета студентов12Проект: Управление библиотекой
Обзор проектаКлассы Book и UserСистема выдачи книгФункционал поискаИнтерфейс администратораТестирование и интеграцияПотренируйтесь самостоятельно: Онлайн-компилятор Python