0

在我的DDD项目中,我试图用java枚举实现状态模式。ddd状态模式验证通知

我在验证具有取决于状态的行为的实体方法时遇到问题。

验证我使用通知模式。

我遵循“始终有效的实体”的方法,以便在每次操作中我首先调用“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()); 
     } 

    } 

时出现的错误是关于状态之间的转换无效怎么能应用(在连词与状态模式)的通知模式?

任何想法?

UPDATE:

我找到了解决办法。我把整个操作取决于实体中的状态,并且将状态模式更细化,仅仅用于所需的代码。通过这种方式,我应用该模式来计算下一个状态,以便我可以检查是否允许转换并应用通知模式。

代码:

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()); 
     } 

    } 

回答

1

我认为你不枚举太多。 除了拥有难以扩展的一组固定状态外,您很难为每个具体状态引入任何形式的合约,这也可以解决您的通知问题。

引入抽象状态类,它是所有具体状态的基类。传递一个上下文,它允许为每个状态设置一个后继状态。这个上下文可以通过你的聚合根来实现。 您的通知可以按照您使用AbstracftState执行的方式由每个州进行管理,例如,通过强制状态执行返回一个通知对象:

interface StateContext { 
    setState(AbstractState state); 
} 

class AbstractState { 
    abstract Notification execute(StateContext context); 
} 

class Task extends AggregateRoot implements StateContext { 
    AbstractState currentState; 

    .... 

    public void start() { 
     Notification n = currentState.execute(this); 
     if (n.hasErrors()) { 
      throw new Exception(n.toErrorReport()); 
     } 
    } 
} 

现在你可以前或执行后,收集每个状态的错误(你可能要为大家介绍的每个AbstractState内的validateStart(),这是执行之前的称呼)和将收集的错误报告给调用者。

+0

Hello @mbnx。你在哪里返回下一个状态?执行“execute”方法不能,因为它返回通知。 – choquero70

+0

可以使用StateContext接口将状态设置为传递给execute方法。 – mbnx

0

我会将TaskWorkflow建模为Task集合中的VO。

class Task { 

    private Workflow workflow; 

    public void start() { 
     workflow = workflow.followWith(Action.START, this); 
    } 

    public State currentState() { 
     return workflow.state(); 
    } 

    public List availableActions() { 
     return workflow.nextActions(); 
    } 

} 

该工作流程是一个FSM,由动作之间的状态转换组成。任何对工作流方法的调用都会创建一个指向新状态的新工作流表示形式。可以将转换模型化为直接或更复杂的涉及业务逻辑的自定义,就像您说的那样。 如果您使用函数式语言,您可以返回Monad来处理错误,但在这种情况下,您可以通过函数式语言进行指定并创建一个,或者只需引发表示聚合消息的异常。

希望它有帮助。

+0

我想你实现工作流对象中的状态模式不是吗?方法followWith是你实现转换的地方吗? – choquero70