В моем проекте DDD я пытаюсь реализовать шаблон состояния с помощью java enum.
У меня возникла проблема при проверке методов сущности, поведение которых зависит от состояния.
Для проверки я использую шаблон уведомления.
Я следую подходу «всегда действительный объект», поэтому в каждой операции я сначала вызываю метод проверки «isValidForOperation».
Вот код, только для простоты:
Организация:
public class Task extends AggregateRoot<TaskId> {
...
private State state;
...
// Operation with behaviour depending on the state
// It's a transition from "ASSIGNED" state to "IN_PROGRESS" state
// I apply the state pattern here
public void start () {
State next = this.state.start ( this );
this.setState ( next );
}
...
}
Перечисление java, моделирующее состояние:
public enum State {
ASSIGNED {
public State start ( Task task ) {
// Validation method to ensure the operation can be done
assertTaskIsValidForStart ( task );
// Business logic
...
// Return the next state
return ( State.IN_PROGRESS );
}
}
...
// more enum values for other states
...
// Default implementation of "start" operation
// It will be executed when the current state is not "ASSIGNED"
// So an error would be generated
public State start ( Task task ) {
// I can't apply notification pattern here !!!
// I would have to throw an exception
}
}
Метод проверки соответствует шаблону уведомления. Он собирает все возможные ошибки в объекте уведомления. Этот объект уведомления передается в исключение. Возникает исключение, а затем прикладной уровень перехватывает его и возвращает клиенту все сообщения об ошибках.
public void assertTaskIsValidForStart ( Task task ) {
Notification notification = new Notification();
if ( errorCondition (task) ) {
notification.addError(...);
}
...
// more errors
...
if ( notification.hasErrors() ) {
throw new TaskNotValidForStartException ( notification.errors() );
}
}
Как может быть применен шаблон уведомления (в сочетании с шаблоном состояния), когда условие ошибки касается недопустимых переходов между состояниями?
Есть идеи?
ОБНОВЛЕНИЕ:
Я нашел решение. Я помещаю всю операцию, которая зависит от состояния, в сущность и применяю шаблон состояния более детально, только к нужному коду. Таким образом, я применяю шаблон для расчета только следующего состояния, чтобы я мог проверить, разрешен ли переход, и также применить шаблон уведомления.
Код:
public class Task extends AggregateRoot<TaskId> {
...
private State state;
...
// Operation with behaviour depending on the state
// It's a transition from "ASSIGNED" state to "IN_PROGRESS" state
// I apply fine-grained state pattern here
public void start () {
// Validation method to ensure the operation can be done
// One of the validations will be if the transition is allowed
assertTaskIsValidForStart ( this );
// Business logic
// If it depends on the state, I would apply state pattern delegating to another method
...
// Set the next state
State next = this.nextStateForStart();
this.setState ( next );
}
...
public State currentState() {
return this.state;
}
...
public State nextStateForStart() {
return this.currentState().nextStateForStart();
}
...
}
public enum State {
ASSIGNED {
public State nextStateForstart() {
return ( State.IN_PROGRESS );
}
}
...
// more enum values for other states
...
// Default implementation of "start" transition
// It will be executed when the current state is not "ASSIGNED"
public State nextStateForstart() {
return null;
}
}
public void assertTaskIsValidForStart ( Task task ) {
Notification notification = new Notification();
// Validate the transition is allowed
if ( task.nextStateForStart() == null ) {
notification.addError(...);
}
...
// more errors
...
if ( notification.hasErrors() ) {
throw new TaskNotValidForStartException ( notification.errors() );
}
}