首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >状态模式验证通知

状态模式验证通知
EN

Stack Overflow用户
提问于 2017-10-12 03:14:46
回答 2查看 591关注 0票数 1

在我的DDD项目中,我试图用java enum实现状态模式。

在验证具有依赖于状态的行为的实体方法时,我遇到了问题。

为了验证,我使用通知模式。

我遵循“始终有效的实体”方法,以便在每个操作中首先调用"isValidForOperation“验证方法。

下面是代码,与简单性相关:

实体:

代码语言:javascript
复制
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 enum对状态进行建模:

代码语言:javascript
复制
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

        }

}

验证方法遵循通知模式。它收集通知对象中所有可能的错误。此通知对象传递给异常。抛出异常,然后应用程序层捕获异常并将所有错误消息返回给客户端。

代码语言:javascript
复制
public void assertTaskIsValidForStart ( Task task ) {

        Notification notification = new Notification();
        if ( errorCondition (task) ) {
            notification.addError(...);
        }
        ...
        // more errors
        ...
        if ( notification.hasErrors() ) {
            throw new TaskNotValidForStartException ( notification.errors() );
        }

    }

当错误条件是关于状态之间无效的转换时,如何应用通知模式(与状态模式合并)?

有什么想法吗?

更新:

我找到了解决办法。我将依赖于实体中状态的整个操作放到实体中,并将状态模式应用到更细粒度的代码中,仅用于所需的代码。这样,我就可以应用模式来计算下一个状态,这样我就可以检查是否允许转换,也可以应用通知模式。

代码:

代码语言:javascript
复制
    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() );
        }

    }
EN

回答 2

Stack Overflow用户

发布于 2017-10-12 05:28:37

我觉得你的枚举做得太多了。除了有一组很难扩展的固定状态之外,您还很难为每个具体状态引入任何形式的合同,这也将解决您的通知问题。

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

代码语言:javascript
复制
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());
        }
    }
}

现在,您可以在执行之前或之后收集每个状态的错误(您可能希望在每个validateStart()中引入一个在执行前调用的AbstractState ()),并向调用方报告收集的错误。

票数 1
EN

Stack Overflow用户

发布于 2017-10-13 02:03:55

我会在任务聚合中将TaskWorkflow建模为VO。

代码语言:javascript
复制
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
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46700832

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档