Apply the status mode to do the project approval process

I recently finished studying the book "Head first to Design Pattern". I just planned to use my spare time to rewrite a project of the company. I wanted to take the opportunity of rebuilding the project to practice. This article is used to record the pits and solutions encountered. .

First introduce the project background, a very simple process, the object is Project, there is a field that marks the approval status as status, according to the business process, go to different stages, each stage corresponds to a value, it is very suitable to use the status mode to achieve .

Paste the diagram in the design pattern book: the terms in it will be used later.

First define the interface, and write the implementation class, and then write the Context, basically copy the code in the book, needless to say. The only change I made was to change the State interface to a normal class, and the overridden method used by ConcreateState at the bottom. The default parent class method throws UnsupportedOperationException. In this way, if you call a method that is not implemented by the subclass, an unsupported operation will be thrown automatically.

Paste my class diagram:

 So how is this state machine linked to the state of the project? There is only one candy machine in the book, but there are many projects. How can each project use the state mode? I took a lot of detours before I discovered the previous misunderstanding, project is candy, status is count, there is no need to have a lot of state machines, as long as it can handle this state.

Then the constructor method of the context can be transformed into the constructor of the incoming project object

    public StateContext(Project project) {
        initialState = new InitialState(this);
        approvalPendingState = new ApprovalPendingState(this);
        approvalFailState = new ApprovalFailState(this);
        biddingState = new BiddingState(this);
        bidFailState = new BidFailState(this);
        implementState = new ImplementState(this);
        finishState = new FinishState(this);
        closedState = new ClosedState(this);
        switch (project.getStatus()) {
            case Project.INITIAL:
                state = initialState;
                break;
            case Project.APPROVAL_PENDING:
                state = approvalPendingState;
                break;
            case Project.APPROVAL_FAIL:
                state = approvalFailState;
                break;
            case Project.BIDDING:
                state = biddingState;
                break;
            case Project.BID_FAIL:
                state = bidFailState;
                break;
            case Project.IMPLEMENT:
                state = implementState;
                break;
            case Project.FINISH:
                state = finishState;
                break;
            case Project.CLOSED:
                state = closedState;
                break;
        }
    }

Then pass Project into each state class,

    public Project apply(Project project){
       return  state.apply(project);
    }

Return after changing within the state class. 

    @Override
    public Project apply(Project project) {
        project.setStatus(Project.APPROVAL_PENDING);
        stateContext.setState(stateContext.getApprovalPendingState());
        return project;
    }

Call it in the Controller as shown below

		try {
			StateContext stateContext = new StateContext(project);
			projectService.save(stateContext.apply(project));
			addMessage(redirectAttributes, "保存项目成功");
		} catch (UnsupportedOperationException e) {
			addMessage(redirectAttributes, "当前阶段不支持此操作");
		}

Before, I thought about putting the Service directly into each Concrete action class, but the problem was that the Service could not be injected, because it was constructed by the constructor, and then I modified the constructor and replaced all of them with injection. However, there is a problem when injecting the state object that saves the current state in the Context. The state is variable, and it is impossible to determine which one should be injected. It was later changed back to the way it was written in the book.

In addition, the state mode also has a framework, which is under sprngboot, and you can try it if you have the opportunity in the future. Finally, the use of workflow is still recommended for writing processes. The problem of using state mode is that there are too many class explosions, and it is inconvenient to write.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325812178&siteId=291194637