Паттерн государственного проектирования: как избежать дублирования кода при использовании entry () и exit ()?
Ситуация: Мои состояния имеют методы entry() и exit(), которые необходимо вызывать каждый раз при переходе состояния. Чтобы убедиться в этом, я использовал метод changeState() в State, который содержит необходимую процедуру. Он вызывается контекстом каждый раз, когда он использует операцию с участием конечного автомата. Однако проблема в том, что мне нужно вызывать state.changeState() каждый раз, когда я добавляю новый метод, и я уверен, что есть способ избежать дублирования кода. Ниже приведен код для дальнейшего пояснения.
class Context {
State state;
void method1() {
state.method1();
state.changeState();
}
void method2() {
state.method2();
state.changeState(); // Code duplication!!
}
abstract class State {
Context context;
State next;
void changeState() {
this.exit();
next.entry();
context.setState(next);
}
// other necessary methods
}
class ConcreteState extends State {
void method1() {
// do something
next = AnotherConcreteState;
}
void entry() {/*do something */};
void exit() {/*do something */};
}
Если я хочу добавить дополнительные методы в Context, что я могу сделать, чтобы избежать дублирования кода вызова state.changeState() каждый раз внутри новых методов?
1 ответ
Вы очень близки. ВchangeState
метод принадлежит к Context
класс, а не State
класс. Вот хорошая статья по теме. Обратите внимание, что диаграмма классов показываетchangeState
в Document
(контекст) класс.
Чтобы было еще чище, changeState
мог взять next
состояние как параметр. Как это:
class Context {
State state;
void method1() {
state.method1();
}
void changeState(next) {
state.exit();
this.state = next;
state.enter();
}
}
abstract class State {
Context context;
// other methods
}
class ConcreteState extends State {
void method1() {
// do something
context.changeState(AnotherConcreteState);
}
void enter() { /* do something */ }
void exit() { /* do something */ }
}
Теперь, когда вы добавляете больше методов в Context
, нет дублирования в Context
. Это выглядело бы так:
class Context {
State state;
void method1() {
state.method1();
}
void method2() {
state.method2();
}
void changeState(next) {
state.exit();
this.state = next;
state.enter();
}
}
abstract class State {
Context context;
// other methods
}
class ConcreteState extends State {
void method1() {
// do something
context.changeState(AnotherConcreteState);
}
void method2() {
// do something else
context.changeState(YetAnotherConcreteState);
}
void enter() { /* do something */ }
void exit() { /* do something */ }
}