java-設計模式-狀態模式-模擬審批流程-二級審批

設計模式的狀態模式,就是把狀態獨立成一個類,代替傳統複雜的if-else。

網上還有非常多關於狀態模式的介紹,不過很多都是點到即止,例子我理解的也不是很清楚。設計模式只是一種思路,掌握好這個思路就可以,實現有非常多種方法。

 

接下來我有項目經典問題-審批流程,來使用下狀態模式。

基本的審批流程如下: 提交表單 -> 一級審批 -> 二級審批 -> 結束

那對應的我也設置了四個狀態: 提交表單狀態、一級審批狀態、二級審批狀態、結束狀態。

狀態定義了三個動作: 同意並進入下一環節(agreeToNext)、駁回上一環節(backToBefore)、結束(finish)

 

接下來我先定義狀態的父類,這裏我用到了抽象類,而非接口,因爲我想狀態有很多通用屬性。很多網上例子會把這些屬性放到Context上下文裏面,通過改變狀態去修改這些屬性,我覺得都可以。

此父類聲明瞭很多狀態的屬性,以及定義了三個動作,但是我把結束動作方法給實現了,因爲我覺得接收動作代碼都是相同的。


/**
 * 提交狀態0->一級審批1->二級審批2 ->審批完成3
 * 狀態
 */
public abstract class Status {
    /**
     * 同意並進入下一環節
     * @param task 任務
     * @param msg 意見
     * @param nextUser 下一環節處理人
     */
    public abstract boolean agreeToNext(ApproveTask task, String msg, String nextUser);

    /**
     * 打回上一環節
     * @param task 任務
     * @param msg 意見
     * @return
     */
    public abstract boolean backToBefore(ApproveTask task, String msg);



    //屬性
    String statusName;//狀態名
    String user;//操作用戶
    String suggest;//意見信息
    String request;//申請信息
    boolean operationFlag;//是否進行了操作
    int statusId = -1;
    boolean agreeFlag;//是否同意
    boolean isFinish;//是否終止狀態
    int nextStatusId = -1;//下一環節 狀態id


    /**
     * 構造方法
     */
    public Status(String user,String request) {
        this.user = user;
        this.request = request;
    }


    /**
     * 結束
     * @param task 任務
     * @param msg 意見
     */
    public boolean finish(ApproveTask task,String msg,boolean agreeFlag){
        System.out.println("環節結束 是否異常:"+agreeFlag);
        task.getApproveStatusList().add(this);//放入審批鏈中
        this.suggest = msg;
        this.agreeFlag = agreeFlag;
        this.nextStatusId = 3;
        this.operationFlag = true;
        //異常終止
        FinishStatus finishStatus = new FinishStatus(this.user,msg,agreeFlag);
        task.setStatus(finishStatus);
        task.getApproveStatusList().add(finishStatus);
        return true;
    }

    @Override
    public String toString() {
        return "狀態名:"+statusName +" 狀態id:"+statusId+" 下一環節id:"+
                nextStatusId+" 操作用戶:"+user
                +" 是否進行了操作:"+operationFlag
                +" 是否同意:"+agreeFlag
                +" 申請信息:"+request
                +" 意見信息:"+ suggest;
    }


}

接下來是具體的狀態類:

提交狀態類


/**
 * 提交狀態0->一級審批1->二級審批2 ->審批完成3
 *
 * 此類是提交狀態
 *
 */
public class SubmitStatus extends Status{

    public SubmitStatus(String user,String request) {
        super(user,request);
        this.statusName = "提交狀態";
        this.statusId = 0;
    }

    @Override
    public boolean agreeToNext(ApproveTask task,String msg,String nextUser){
        System.out.println("提交環節同意");
        this.operationFlag = true;
        this.agreeFlag = true;//
        this.suggest = msg;
        this.nextStatusId = statusId + 1;//下級狀態
        task.getApproveStatusList().add(this);//放入審批路徑
        task.setStatus(new FirstApproveStatus(nextUser,suggest));//設置下級審批,當前的意見成爲下一審批人的申請信息
        return true;
    }

    @Override
    public boolean backToBefore(ApproveTask task,String msg){
        System.out.println("提交環節,不能打回");
        return false;
    }

}

一級審批狀態類:


/**
 * 提交狀態0->一級審批1->二級審批2 ->審批完成3
 * 一級審批
 */
public class FirstApproveStatus extends Status{

    /**
     * 構造方法
     *
     * @param user
     */
    public FirstApproveStatus(String user,String request) {
        super(user,request);
        this.statusName = "一級審批";
        this.statusId = 1;
    }

    @Override
    public boolean agreeToNext(ApproveTask task, String msg, String nextUser) {
        System.out.println("一級審批同意");
        this.agreeFlag = true;//
        this.operationFlag = true;
        this.suggest = msg;
        this.nextStatusId = statusId + 1;//下級狀態
        task.getApproveStatusList().add(this);//放入審批路徑
        task.setStatus(new SecondApproveStatus(nextUser,this.suggest));//設置下級審批
        return true;
    }

    @Override
    public boolean backToBefore(ApproveTask task, String msg) {
        System.out.println("一級審批迴退");
        this.agreeFlag = false;
        this.operationFlag = true;
        this.suggest = msg;
        this.nextStatusId = statusId -1;
        String beforeUserId = task.getApproveStatusList().get(task.getApproveStatusList().size() - 1).user;
        task.getApproveStatusList().add(this);
        task.setStatus(new SubmitStatus(beforeUserId,this.suggest));
        return true;
    }

}

二級審批狀態類:


public class SecondApproveStatus extends Status {
    /**
     * 構造方法
     *
     * @param user
     */
    public SecondApproveStatus(String user,String request) {
        super(user,request);
        this.statusName = "二級審批";
        this.statusId = 2;
    }

    @Override
    public boolean agreeToNext(ApproveTask task, String msg, String nextUser) {
        System.out.println("二級審批同意");
       /* this.agreeFlag = true;//
        this.suggest = msg;
        this.nextStatusId = statusId + 1;//下級狀態
        task.getApproveStatusList().add(this);//放入審批路徑
        Status finishStatus = new FinishStatus(this.user,this.suggest,true);
        task.setStatus(finishStatus);//設置下級審批
        task.getApproveStatusList().add(finishStatus);//放入審批路徑
        */
       this.finish(task,msg,true);
        return true;
    }

    @Override
    public boolean backToBefore(ApproveTask task, String msg) {
        System.out.println("二級審批迴退");
        this.agreeFlag = false;
        this.suggest = msg;
        this.nextStatusId = statusId -1;
        this.operationFlag = true;
        String beforeUserId = task.getApproveStatusList().get(task.getApproveStatusList().size() - 1).user;
        task.getApproveStatusList().add(this);
        task.setStatus(new FirstApproveStatus(beforeUserId,this.suggest));
        return true;
    }


}

結束狀態類:


/**
 * 提交狀態0->一級審批1->二級審批2 ->審批完成3
 * 一級審批
 */
public class FirstApproveStatus extends Status{

    /**
     * 構造方法
     *
     * @param user
     */
    public FirstApproveStatus(String user,String request) {
        super(user,request);
        this.statusName = "一級審批";
        this.statusId = 1;
    }

    @Override
    public boolean agreeToNext(ApproveTask task, String msg, String nextUser) {
        System.out.println("一級審批同意");
        this.agreeFlag = true;//
        this.operationFlag = true;
        this.suggest = msg;
        this.nextStatusId = statusId + 1;//下級狀態
        task.getApproveStatusList().add(this);//放入審批路徑
        task.setStatus(new SecondApproveStatus(nextUser,this.suggest));//設置下級審批
        return true;
    }

    @Override
    public boolean backToBefore(ApproveTask task, String msg) {
        System.out.println("一級審批迴退");
        this.agreeFlag = false;
        this.operationFlag = true;
        this.suggest = msg;
        this.nextStatusId = statusId -1;
        String beforeUserId = task.getApproveStatusList().get(task.getApproveStatusList().size() - 1).user;
        task.getApproveStatusList().add(this);
        task.setStatus(new SubmitStatus(beforeUserId,this.suggest));
        return true;
    }

}

接下來是任務類,也就是很多網絡例子的Context上下文 或環境。

這個類有當前的狀態、還有整個審批狀態流的屬性,還有提供對外的 同意、駁回、拒絕等操作,外部只需要對此類進行操作即可


import java.util.ArrayList;
import java.util.List;

/**
 * 審批任務 相當於 狀態模式的Context 環境
 *
 */
public class ApproveTask {
    private Status status;//當前的狀態
    private List<Status> approveStatusList = new ArrayList<>();//審批操作人 此處可以擴展

    /**
     * 任務 構造函數
     */
    public ApproveTask(String user){
        this.status = new SubmitStatus(user,null);
    }
    /**
     * 同意 要寫同意意見
     * @param msg 同意意見
     */
    public void agree(String msg,String nextUser){
        status.agreeToNext(this,msg,nextUser);
    }

    /**
     * 駁回
     * @param msg
     */
    public void back(String msg){
        status.backToBefore(this,msg);
    }

    public void refuse(String msg){
        status.finish(this,msg,false);
    }

    /**
     * 打印審批路徑
     */
    public void showApprovePath(){
        approveStatusList.stream().forEach(System.out::println);
    }
    //getter and setter


    public Status getStatus() {
        return status;
    }

    public void setStatus(Status status) {
        this.status = status;
    }

    public List<Status> getApproveStatusList() {
        return approveStatusList;
    }

    public void setApproveStatusList(List<Status> approveStatusList) {
        this.approveStatusList = approveStatusList;
    }
}

測試方法1(正常二級審批流程):

 public static void normal(){
        System.out.println("---------正常流程----------");
        ApproveTask approveTask = new ApproveTask("小紅");//小紅新建個審批任務
        approveTask.agree("由於工作需要,申請對工程機進行使用 3天","小明");//小紅寫申請書,提交給 小明
        approveTask.agree("小紅需要對工程師進行使用,初步決定可以","小亮");//小明一級審批同意,併發送給小亮
        approveTask.agree("情況屬實,可以批准",null);//小亮審批同意

        System.out.println();
        System.out.println("----整體審批路徑如下----");
        approveTask.showApprovePath();
    }

運行結果:

---------正常流程----------
提交環節同意
一級審批同意
二級審批同意
環節結束 是否異常:true

----整體審批路徑如下----
狀態名:提交狀態 狀態id:0 下一環節id:1 操作用戶:小紅 是否進行了操作:true 是否同意:true 申請信息:null 意見信息:由於工作需要,申請對工程機進行使用 3天
狀態名:一級審批 狀態id:1 下一環節id:2 操作用戶:小明 是否進行了操作:true 是否同意:true 申請信息:由於工作需要,申請對工程機進行使用 3天 意見信息:小紅需要對工程師進行使用,初步決定可以
狀態名:二級審批 狀態id:2 下一環節id:3 操作用戶:小亮 是否進行了操作:true 是否同意:true 申請信息:小紅需要對工程師進行使用,初步決定可以 意見信息:情況屬實,可以批准
狀態名:結束環境 狀態id:-1 下一環節id:-1 操作用戶:小亮 是否進行了操作:true 是否同意:true 申請信息:情況屬實,可以批准 意見信息:null

測試方法2(駁回例子):

public static void back(){
        System.out.println("---------駁回流程--------");
        System.out.println("新建任務");
        ApproveTask approveTask = new ApproveTask("小紅");//小紅新建個審批任務
        System.out.println("現在的任務狀態:"+approveTask.getStatus());
        approveTask.agree("由於工作需要,申請對工程機進行使用 3天","小明");//小紅寫申請書,提交給 小明
        System.out.println("現在的任務狀態:"+approveTask.getStatus());
        approveTask.agree("小紅需要對工程師進行使用,初步決定可以","小亮");//小明一級審批同意,併發送給小亮
        System.out.println("現在的任務狀態:"+approveTask.getStatus());
        approveTask.back("不行呀,請再檢查檢查");//小亮 二級審批不同意
        System.out.println("現在的任務狀態:"+approveTask.getStatus());
        approveTask.agree("已經檢查過庫存了,確定可以","小亮");//小明一級審批再次同意
        System.out.println("現在的任務狀態:"+approveTask.getStatus());
        approveTask.agree("情況屬實,可以批准",null);//小亮審批同意

        System.out.println();
        System.out.println("----整體審批路徑如下----");
        approveTask.showApprovePath();
    }

運行結果:

---------駁回流程--------
新建任務
現在的任務狀態:狀態名:提交狀態 狀態id:0 下一環節id:-1 操作用戶:小紅 是否進行了操作:false 是否同意:false 申請信息:null 意見信息:null
提交環節同意
現在的任務狀態:狀態名:一級審批 狀態id:1 下一環節id:-1 操作用戶:小明 是否進行了操作:false 是否同意:false 申請信息:由於工作需要,申請對工程機進行使用 3天 意見信息:null
一級審批同意
現在的任務狀態:狀態名:二級審批 狀態id:2 下一環節id:-1 操作用戶:小亮 是否進行了操作:false 是否同意:false 申請信息:小紅需要對工程師進行使用,初步決定可以 意見信息:null
二級審批迴退
現在的任務狀態:狀態名:一級審批 狀態id:1 下一環節id:-1 操作用戶:小明 是否進行了操作:false 是否同意:false 申請信息:不行呀,請再檢查檢查 意見信息:null
一級審批同意
現在的任務狀態:狀態名:二級審批 狀態id:2 下一環節id:-1 操作用戶:小亮 是否進行了操作:false 是否同意:false 申請信息:已經檢查過庫存了,確定可以 意見信息:null
二級審批同意
環節結束 是否異常:true

----整體審批路徑如下----
狀態名:提交狀態 狀態id:0 下一環節id:1 操作用戶:小紅 是否進行了操作:true 是否同意:true 申請信息:null 意見信息:由於工作需要,申請對工程機進行使用 3天
狀態名:一級審批 狀態id:1 下一環節id:2 操作用戶:小明 是否進行了操作:true 是否同意:true 申請信息:由於工作需要,申請對工程機進行使用 3天 意見信息:小紅需要對工程師進行使用,初步決定可以
狀態名:二級審批 狀態id:2 下一環節id:1 操作用戶:小亮 是否進行了操作:true 是否同意:false 申請信息:小紅需要對工程師進行使用,初步決定可以 意見信息:不行呀,請再檢查檢查
狀態名:一級審批 狀態id:1 下一環節id:2 操作用戶:小明 是否進行了操作:true 是否同意:true 申請信息:不行呀,請再檢查檢查 意見信息:已經檢查過庫存了,確定可以
狀態名:二級審批 狀態id:2 下一環節id:3 操作用戶:小亮 是否進行了操作:true 是否同意:true 申請信息:已經檢查過庫存了,確定可以 意見信息:情況屬實,可以批准
狀態名:結束環境 狀態id:-1 下一環節id:-1 操作用戶:小亮 是否進行了操作:true 是否同意:true 申請信息:情況屬實,可以批准 意見信息:null

 

小結:

以上就是狀態模式模擬審批流程的簡單例子。

當然,有很多優化的地方,比如 駁回可以選擇駁回環節、任務類需要可以進行序列化和反序列化,可以把任務結果保存入數據庫中,並且可以根據數據庫中存入的值還原成任務類等操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章