應用狀態模式作項目審批流程

最近學完《Head first to Design Pattern》這本書,正好打算利用業餘時間重寫公司的一個項目,就想拿着重建項目的機會練下手,此文用來記錄下遇到的坑和解決方案。java

首先介紹下項目背景,一個很簡單的流程,對象是Project,有一個標記審批狀態的字段爲status,根據業務流程,轉到不一樣的階段,每一個階段對應一個值,很適合用狀態模式來實現。設計模式

貼一下設計模式書中的圖:裏面的術語下文要用到。app

首先先定義接口,並寫好實現類,而後把Context也寫好,基本上都是照抄書上代碼,毋庸多言。我惟一作了改動的是把State接口改爲了普通類,底下的ConcreateState用的覆蓋的方法。默認父類方法裏都是拋出UnsupportedOperationException。這樣若是調用子類沒有實現的方法時,會自動拋出不支持的操做。框架

貼一下個人類圖:ide

 那麼這個狀態機是如何跟project的狀態掛接起來的呢,書中的糖果機只一個,而project有不少個,怎麼讓每一個project都能用上狀態模式呢?我繞了不少彎路,才發現以前的誤區,project就是糖果,status就是count,狀態機不須要有不少個,只要能處理這個狀態就好了。this

那麼context的構造器方法就能夠改形成傳入project對象的構造器設計

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

而後把Project傳入每一個狀態類,code

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

在狀態類內改變後再返回。 對象

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

在Controller裏以下圖調用接口

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

以前我曾經想過把Service直接放到每一個Concrete動做類裏去,可是存在的問題是無法注入Service,由於都是構造方法構造出來的,而後我又改造構造方法,所有換成注入的,可是在注入Context裏保存當前狀態的state對象時遇到問題了,state是可變的,無法肯定應該注入哪個。後來全又改回書上的寫法了。

另外狀態模式也有框架,是在sprngboot下的,之後有機會能夠嘗試一下。最後寫流程仍是提倡使用工做流,使用狀態模式的問題是類爆炸太多,寫起來也不方便。

相關文章
相關標籤/搜索