В этом уроке мы рассмотрим еще один популярный шаблон поведенческого дизайна — State Design Pattern.
Знание шаблона проектирования состояний оказывается полезным, когда мы работаем с объектом, который может существовать в нескольких состояниях. Мы должны использовать его в первую очередь, когда поведение объекта зависит от его текущего состояния. Этот шаблон помогает нам избежать длительных условных проверок состояния объекта в методах этого класса.
С этим, давайте начнем!
Государственный шаблон проектирования:
Мы можем представить шаблон проектирования состояния с помощью следующей диаграммы UML:

Куда,
- Состояние — представляет абстрактный класс или интерфейс для объявления минимальной ожидаемой функциональности для каждого конкретного объекта состояния.
- ConcreteState — это классы реализации для государства
- Контекст — это класс, который мы выставляем миру, и обычно он отвечает за поддержание текущего состояния экземпляра. Он также делегирует ответственность конкретным государственным классам для выполнения задачи.
Пример реализации:
Допустим, у нас есть автоматический дозатор мыла. В идеале он может существовать в этих состояниях — Ideal , Dispensing или OutOfStock . Давайте визуализируем это с помощью диаграммы состояний:

Определение состояний классов:
Сначала мы определим наш интерфейс DispenserState :
|
1
2
3
4
5
|
public DispenserState { void sensesHand(AutoDispenser autoDispenser); void stopsSensingHand(AutoDispenser autoDispenser);} |
Каждый из наших классов состояний должен реализовывать DispenserState и определять поведение для этого состояния. Наш класс IdleState будет выглядеть так:
|
01
02
03
04
05
06
07
08
09
10
11
12
|
public class IdleState implements DispenserState { public void sensesHand(AutoDispenser autoDispenser) { System.out.println("Hand sensed"); autoDispenser.startDispensing(); autoDispenser.setDispenserState(autoDispenser.getDispensingState()); } public void stopsSensingHand(AutoDispenser autoDispenser) { System.out.println("Sensor inactive already!"); }} |
Точно так же мы можем определить два других наших класса, представляющих состояние:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class DispensingState implements DispenserState { public void sensesHand(AutoDispenser autoDispenser) { System.out.println("Already dispensing"); } public void stopsSensingHand(AutoDispenser autoDispenser) { System.out.println("Stopped sensing"); autoDispenser.stopDispensing(); if(autoDispenser.getQuantity() > 1) { autoDispenser.setDispenserState(autoDispenser.getIdleState()); } else { autoDispenser.setDispenserState(autoDispenser.getOutOfStockState()); } }} public class OutOfStockState implements DispenserState { public void sensesHand(AutoDispenser autoDispenser) { System.out.println("nothing to dispense"); } public void stopsSensingHand(AutoDispenser soapDispenser) { System.out.println("dispenser is already inactive"); }} |
Определение контекста:
Наконец, давайте определим наш контекстный класс — AutoDispenser , который будет взаимодействовать с клиентским кодом:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
public class AutoDispenser { private IdleState idleState; private DispensingState dispensingState; private OutOfStockState outOfStockState; private DispenserState currentDispenserState; public AutoDispenser() { this.idleState = new IdleState(); this.dispensingState = new DispensingState(); this.outOfStockState = new OutOfStockState(); if(getQuantity() > 0) { this.currentDispenserState = idleState; } else { this.currentDispenserState = outOfStockState; } } public int getQuantity() { //returns current soap quantity ... } public void startDispensing() { ... } public void stopDispensing() { ... } public void sensesHand() { this.currentDispenserState.sensesHand(this); } public void stopsSensingHand() { this.currentDispenserState.stopsSensingHand(this); } } |
Здесь мы поддерживаем текущее состояние нашего автоматического диспенсера и вызываем метод в конкретном классе состояний для выполнения операции.
Почему Государственный Образец?
Помимо того, что мы помогаем избежать длительных условий, он также предоставляет и другие преимущества:
- Добавить новое состояние очень легко и просто, так как нам просто нужно определить другой конкретный класс состояний
- Точно так же удаление состояния потребует только удаления связанного класса
- Делает код легче читать и следовать
- Отличная демонстрация принципа единой ответственности
Вывод:
Как программисту, для нас действительно важно выбрать правильный шаблон проектирования для решения любой проблемы проектирования.
В этом быстром уроке мы рассмотрели шаблон State State. Мы узнали, как и когда это реализовать.
|
Опубликовано на Java Code Geeks с разрешения Шубхры Шриваставы, партнера нашей программы JCG . Смотрите оригинальную статью здесь: State Design Pattern In Java Мнения, высказанные участниками Java Code Geeks, являются их собственными. |