В этом уроке мы рассмотрим еще один популярный шаблон поведенческого дизайна — 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, являются их собственными. |