EventBus-實現java狀態機

摘自:https://www.jianshu.com/p/8def04b34b3cjava

首先,瞭解狀態機是什麼,咱們爲何須要狀態機!
舉個最簡單例子,請假,做爲一個最底層程序員,每次請假都要領導層層審批,而假有分爲不少種,事假,病假,婚假,年休假等等,固然選擇請的假不一樣,審批標準也不一樣,不一樣的假單須要走的審批鏈也不同,好比年休假,可能只須要領導審批扣掉年休假便可,請病假須要領導審批,領導審批以後,先休假,等休完假回來提交病假的材料,由hr審批以後才能完成整個請假過程。更有甚者,若是你要修一個一個月的長假,就不只僅是須要直線領導hr審批,可能還須要公司ceo審批 ,審批經過後,才能經過。以下圖:git


固然,實際來說,請假的種類和鏈路比這個要複雜的多,咱們通常會怎麼實現,是否要使用if else了,對應不一樣的假單,走不一樣的分支,代碼寫出來就成了一個很是複雜的,多級嵌套的代碼了,後面如何維護代碼,多了幾種假的種類,是否是又要if else了。以下代碼:
 public void requestLeavePermit(String type){
        if(type.equals("事假")){
            //領導審批->hr審批->ceo審批->完成
        }else if(type.equals("病假")){
              //領導審批->休假->補充病例->hr審批->完成
        }else if(type.equals("年休假")){
               //領導審批->hr審批->經過
        }else if(type.equals("產假")){
            //領導審批->hr審批->經過
        }else if(type.equals("調休假")){
              //領導審批->ceo審批->經過
        }
    }

  或者寫成這個樣子:程序員

public void requestLeavePermit(String type,String userName){
        switch (type){
            case "事假":
                       //領導審批->hr審批->ceo審批->完成
                    break;
            case "病假":
                        //領導審批->休假->補充病例->hr審批->完成
                    break;
            case "年休假":
                        //領導審批->hr審批->經過
                    break;
            case "產假":
                      //領導審批->hr審批->經過
                    break;
            case "調休假":
                    //領導審批->ceo審批->經過
            default:
                    break;
        }
    }

  

if,else嵌套太深,而後每一個if,else又是本身的處理流程,這樣代碼結構會原來越複雜,當審批鏈發生變動,這個時候會發現代碼耦合性太強,致使修改起來很麻煩。
如何解決這個問題,咱們不難看到,全部的請假都通過了這樣幾個階段,從請假開始,提交假單,而後領導審批,hr審批,ceo審批,只是不一樣的是,有些審批流程多了審覈人或者是少了審覈人,每種假單審覈材料有所不一樣而已。
咱們如何使用狀態機來如何解決代碼耦合性的問題,提升代碼可擴展性可讀性
若是咱們把領導審批,hr審批,ceo審批,分別看作一個動做,每一個相應都有幾個狀態,審批經過,不經過,拒絕,從新審覈,會怎麼樣?

首先,咱們將請假的類型定義成一個枚舉:
public enum LeavePermitEnum {

    ANNUAL_LEAVE("annual_leave","年休假 "),
    CASUAL_LEAVE("casual_leave","事假"),
    MEDICAL_LEAVE("medical_leave","病假"),
    MARRIAGE_LEAVE("marriage_leave","婚假"),;

    private String type;
    private String memo;
    //此處忽略構造方法和set/get方法
}

領導審批,hr審批,ceo審批,都有一個審批意見(經過,拒絕,或者是重修修改假單補充材料等),在這裏,至關於一個事件Event,因而,整個狀態扭轉也能夠用一個枚舉類來表示,審批意見由一個枚舉類Event來表示。github

public enum Event {

    AGREE("agree","贊成"),
    DISSAGREE("disagree","不一樣意"),
    MODIFY("modify","修改"),
    ;
    private String type;
    private String memo;
}

  所以,一個假單的狀態就有不少種,用一個枚舉表明整個假單的狀態:ide

public enum Status {
    //提交假單
    PERMIT_SUBMIT("permitSubmit","提交假單"),
     //領導審批
    LEADER_PERMITING("leaderPermiting","領導審批中"),
    LEADER_PERMIT_AGREE("leaderAgree","領導贊成"),
    LEADER_PERMIT_DISAGREE("leaderDisAgree","領導不一樣意"),
    LEADER_PERMIT_MODIFY("leaderModify","領導以爲須要補充材料重修修改"),

    //hr審批
    HR_PERMITING("hrPermiting","hr審批中"),
    HR_PERMIT_AGREE("hrAgree","hr贊成"),
    HR_PERMIT_DISAGREE("hrDisAgree","hr不一樣意"),
    HR_PERMIT_MODIFY("hrModify","hr以爲須要補充材料重修修改"),
    //ceo審批
    CEO_PERMITING("ceoPermiting","領導審批中"),
    CEO_PERMIT_AGREE("ceoAgree","ceo贊成"),
    CEO_PERMIT_DISAGREE("ceoDisAgree","ceo不一樣意"),
    CEO_PERMIT_MODIFY("ceoModify","ceo以爲須要補充材料重修修改"),

    //最終請假狀態
    PERMIT_SUCCESS("permitSuccess","請假成功"),
    PERMIT_FAIL("permitFail","請假失敗")
    ;

    private String status;
    private String memo;

    private Status(String status,String memo){
        this.status=status;
        this.memo=memo;
    }
}

  

狀態定義清楚以後,須要考慮兩個問題post

  • 從當前狀態須要可以跳轉到下一個狀態,好比提交假單以後,要可以從提交假單狀態跳轉到領導審批狀態。
  • 不一樣的審批意見要可以跳轉不一樣的狀態,好比領導審批狀態跳轉審批經過,或者拒絕該審批須要可以按照Event狀態跳轉不一樣的狀態。

這塊功能能夠交給狀態機StatusMachine去解決,由當前狀態+事件驅動(也就是當前請假的狀態和審批意見)獲取下一個狀態。ui

咱們知道,請假的種類不一樣,所走的流程也不一樣,相應的處理也不一樣,每種假單都有本身的審批鏈,也對應每種假單有不一樣的狀態機,不難設計StatusMachine爲接口或抽象類。狀態機只作一件事情,根據event(審批意見),跳轉下一個狀態機。this

public interface StatusMachine {
      /**
          *@params status 當前狀態
          *@params event 審批意見
          *@return 下一個狀態
       **/
     public Status getNextStatus(Status status,Event event);
}

  

這裏舉兩個例子,一個病假,一個年休假的實現:設計

年休假的審批流程:code

  • 提交假單 PERMIT_SUBMIT
  • 領導審批 LEADER_PERMITING
  • 等待領導審批
  • 領導審批經過/不經過/拒絕
  • 領導審批經過 LEADER_PERMIT_AGREE
  • ceo審批 CEO_PERMITING
  • 等待ceo審批意見
  • ceo審批經過/不經過/拒絕
  • ceo審批經過 CEO_PERMIT_AGREE
  • 請假完成 PERMIT_SUCCESS

所以事假的狀態機StatusMachine實現以下:



public class AnnualLeaveStatusMachine implements StatusMachine{


    public Status getNextStatus(Status status,Event event){
        switch (status){

            case PERMIT_SUBMIT:
                //提交假單狀態無需審批跳轉領導審批中狀態
                return Status.LEADER_PERMITING;

            case LEADER_PERMITING:
                //領導審批須要審批意見 審批意見不用返回不一樣的狀態
                return getLeaderPermitStatus(event);
            case LEADER_PERMIT_AGREE:
                //領導贊成請假,則跳轉ceo審批
                return Status.CEO_PERMITING;
            case LEADER_PERMIT_DISAGREE:
                //領導不一樣意該假單,則請假失敗
                return Status.PERMIT_FAIL;
            case LEADER_PERMIT_MODIFY:
                return getLeaderPermitStatus(event);

            case CEO_PERMITING:
                //ceo審批須要審批意見
                return getCEOPermitStatus(event);
            case CEO_PERMIT_AGREE:
                // ceo審批贊成 跳轉審批經過 請假完成
                return Status.PERMIT_SUCCESS;
            
            case CEO_PERMIT_DISAGREE:
                //ceo不一樣意審批 則跳轉審批失敗
                return Status.PERMIT_FAIL;
            case CEO_PERMIT_MODIFY:
                return  getCEOPermitStatus(event);

            default:
                throw new RuntimeException("沒有該流程");
        }
    }



    private Status getLeaderPermitStatus(Event event){
        switch (event){
            case AGREE:
                //領導審批經過 返回贊成該假單
                return Status.LEADER_PERMIT_AGREE;
            case DISSAGREE:
                //領導不一樣意 則返回領導拒絕改假單狀態
                return Status.LEADER_PERMIT_DISAGREE;
            case MODIFY:
                return Status.LEADER_PERMIT_MODIFY;
            default:
                throw new RuntimeException("不支持該Event審批意見");
        }
    }


    private Status getCEOPermitStatus(Event event){
        switch (event){
            case AGREE:
                //ceo審批經過 則返回ceo贊成該假單
                return Status.CEO_PERMIT_AGREE;
            case DISSAGREE:
                // ceo審批不經過 則返回ceo不一樣意該假單狀態
                return Status.CEO_PERMIT_DISAGREE;
            case MODIFY:
                return Status.CEO_PERMIT_MODIFY;
            default:
                throw new RuntimeException("不支持該Event審批意見");
        }
    }
}

  

病假的審批流程:

  • 提交假單 PERMIT_SUBMIT
  • 領導審批 LEADER_PERMITING
  • 等待領導審批
  • 領導審批經過/不經過/拒絕
  • 領導審批經過 LEADER_PERMIT_AGREE
  • HR審批 HR_PERMITING
  • 等待HR審批意見
  • HR審批經過/不經過/拒絕
  • HR審批經過 CEO_PERMIT_AGREE
  • 請假完成 PERMIT_SUCCESS
    根據該流程不難設計出該狀態機


public class MedicalLeaveStatusMachine implements StatusMachine{

    public Status getNextStatus(Status status,Event event){
        switch (status){
            case PERMIT_SUBMIT:
                    //提交假單狀態直接跳轉領導審批中狀態
                    return Status.LEADER_PERMITING;


            case LEADER_PERMITING:
                    //領導審批中狀態須要審批意見再獲取下一個狀態
                    return getLeaderPermitStatus(event);
            case LEADER_PERMIT_AGREE:
                    //領導贊成審批該假單 跳轉hr審批中狀態
                    return Status.HR_PERMITING; 
            case LEADER_PERMIT_DISAGREE:
                    //領導不一樣意則返回請假失敗
                    return Status.PERMIT_FAIL;
            case LEADER_PERMIT_MODIFY:
                    return  getLeaderPermitStatus(event);

            case HR_PERMITING:
                //hr審批根據審批意見跳轉下一個狀態
                return getHrPermitStatus(event);
            case HR_PERMIT_AGREE:
                //hr審批經過跳轉審批完成狀態
                return Status.PERMIT_SUCCESS;
            case HR_PERMIT_DISAGREE:
                // hr審批不一樣意 返回請假失敗
                return Status.PERMIT_FAIL;
            case HR_PERMIT_MODIFY:
                return  getHrPermitStatus(event);

            default:
                throw new RuntimeException("沒有該流程");
        }
    }
    private Status getLeaderPermitStatus(Event event){
        switch (event){
            case AGREE:
                //領導贊成該假單,則返回領導審批經過
                return Status.LEADER_PERMIT_AGREE;
            case DISSAGREE:
                //領導不一樣意該假單 則返回領導審批不經過
                return Status.LEADER_PERMIT_DISAGREE;
            case MODIFY:
                return Status.LEADER_PERMIT_MODIFY;
            default:
                throw new RuntimeException("不支持該Event審批意見");
        }
    }
    private Status getHrPermitStatus(Event event){
        switch (event){
            case AGREE:
                //hr審批贊成該假單,則返回hr贊成狀態
                return Status.HR_PERMIT_AGREE;
            case DISSAGREE:
                //hr審批不一樣意該假單,則返回hr不一樣意狀態
                return Status.HR_PERMIT_DISAGREE;
            case MODIFY:
                return Status.HR_PERMIT_MODIFY;
            default:
                throw new RuntimeException("不支持該Event審批意見");
        }
    }
}

  對於請假的員工來說,只知道提交了一個假單,並不會關心到底該流程怎麼走,因此在設計的時候,須要根據請假類型可以自動匹配狀態機,這裏能夠用靜態工廠去實現。

public class StatusMachineFactory {

    private StatusMachineFactory(){

    }

    /**
     * 根據狀態獲取狀態機
     * @param leavePermitType
     * @return 對應請假類型的狀態機
     */
    public static StatusMachine getStatusMachine(LeavePermitType leavePermitType){
        switch (leavePermitType){
            case MEDICAL_LEAVE:
                return new MedicalLeaveStatusMachine();
            case ANNUAL_LEAVE:
                return new AnnualLeaveStatusMachine();
            default:
                throw new RuntimeException("未知類型");
        }
    }
}

  

狀態機設計好以後,每一個狀態都應該對應有該狀態的處理類,且須要統一管理該狀態和處理類的關係。
以年休假爲例:提交假單->領導審批4個狀態->ceo審批4個狀態->請假完成/失敗2個狀態。

總計須要11個狀態處理對象去處理該狀態。

該狀態處理類須要具有哪些能力

  • 處理該狀態的業務
  • 可以決定要不要扭轉該狀態機接着往下走(提交假單狀態處理結束要可以自動運行到領導審批狀態,領導審批狀態不能接着扭轉到下一個狀態,須要等待領導的審批意見纔可繼續往下走)

不難設計,先抽象出一個StatusHandler接口或父類,每一個狀態的處理類去實現該接口或繼承該父類,在statusHandler中,有三個方法,before,dohandler,after,after主要負責扭轉狀態機,獲取下一個狀態的處理類處理下一個狀態的事件。若是狀態到達某一個狀態不須要往下繼續執行,則重寫after方法便可中斷狀態機,dohandler主要負責作業務處理。

 
       
public interface AbstractStatusHandler {
    public void handle(LeavePermit leavePermit);
}

public abstract class StatusHandler implements AbstractStatusHandler{

    protected void before(LeavePermit leavePermit){
    }


    public void handle(LeavePermit leavePermit){
        before(leavePermit);
        doHandler(leavePermit);
        after(leavePermit);
    }
    protected abstract void doHandler(LeavePermit leavePermit);

    protected void after(LeavePermit leavePermit){
        //去下一個狀態的處理對象處理
        goNextStatusHandler(leavePermit);
    }

    protected void goNextStatusHandler(LeavePermit leavePermit){
        //獲取下一個狀態
        leavePermit.setStatus(StatusMachineFactory.getStatusMachine(leavePermit.getLeavePermitType()).getNextStatus(leavePermit.getStatus(),leavePermit.getEvent()));
        //狀態機引擎驅動假單處理
        StatusMachineEngine.post(leavePermit);
    }

  在看一下具體的狀態處理類實現,11個狀態對應11個處理類,這裏列舉出部分

public class AnnualPermitSubmitStatusHandler extends StatusHandler{

    protected void doHandler(LeavePermit leavePermit){
        System.out.println(String.format("user:%s--提交年休假假單--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus()));
    }

}

public class AnnualLeaderPermitingStatusHandler extends StatusHandler{

    protected void doHandler(LeavePermit leavePermit){
        System.out.println(String.format("user:%s--領導審批年休假中--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus()));
    }
    @Override
    protected void after(LeavePermit leavePermit){
        if(leavePermit.getEvent()==null){
            //還未審批,狀態機結束,等待審批意見
            System.out.println(String.format("user:%s--等待領導審批--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus()));
            return;
        }
       super.goNextStatusHandler(leavePermit);
    }
}

public class AnnualLeaderAgreeStatusHandler extends StatusHandler{

    protected void doHandler(LeavePermit leavePermit){
        System.out.println(String.format("user:%s--直線領導贊成請年休假--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus()));
    }

}
public class AnnualLeaderAgreeStatusHandler extends StatusHandler{

    protected void doHandler(LeavePermit leavePermit){
        leavePermit.setEvent(null);
        System.out.println(String.format("user:%s--直線領導贊成請年休假--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus()));
    }

}

public class AnnualCEOPermitingStatusHandler extends StatusHandler{
    

    protected void doHandler(LeavePermit leavePermit){
        System.out.println(String.format("user:%s--ceo審批年休假中--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus()));

    }

    protected void after(LeavePermit leavePermit){
       if(leavePermit.getEvent()==null){
           //還未審批,狀態機結束,等待審批意見
           System.out.println(String.format("user:%s--等待ceo審批--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus()));
           return;
       }
        goNextStatusHandler(leavePermit);
    }

}
public class AnnualCEOAgreeStatusHandler extends StatusHandler{

    protected void doHandler(LeavePermit leavePermit){
        System.out.println(String.format("user:%s--ceo贊成休年休假--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus()));
    }

}

public class AnnualPermitSuccessStatusHandler extends StatusHandler{

    @Override
    protected void doHandler(LeavePermit leavePermit){
        System.out.println(String.format("user:%s--請年休假假成功--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus(),leavePermit.getStatus().getMemo()));
    }
    @Override
    protected void after(LeavePermit leavePermit){
    }
}

  關於假單的請求,都會由StatusMachineEngine.post(LeavePermit)去處理,這裏是如何作到按照請假類型,和狀態找到對應的statusHandler的?
這裏是使用eventbus去實現(基於消息訂閱發佈模式實現)

public class StatusMachineEngine {

    private static EventBus eventBus;
    static{
        eventBus = new EventBus();
    }

    /**
     * 發佈一條假單
     * @param leavePermit
     */
    public static void post(LeavePermit leavePermit) {
        eventBus.post(leavePermit);
    }

    /**
     * 假單處理類
     * @param statusLeavePermitHandler
     */
    public static void addListener(LeavePermitHandler statusLeavePermitHandler) {
        eventBus.register(statusLeavePermitHandler);
    }
}

  全部假單的處理都會交給LeavePermitHandler去處理,這個對象裏按照請假類型和請假狀態作路由,選擇不一樣的statusHandler處理業務邏輯。

public class LeavePermitHandler {

    //處理假單 註解表明能夠接受到StatusMachineEngine發佈的假單
    @Subscribe
    @AllowConcurrentEvents
    public void handle(LeavePermit leavePermit){
        //獲取到狀態處理類,而後去處理 handler爲StatusHandler的入口
        getStatusHandler(leavePermit).handle(leavePermit);
    }

    /**
     * 根據假單獲取StatusHandler 狀態處理對象
     * @param leavePermit
     * @return
     */
    public static StatusHandler getStatusHandler(LeavePermit leavePermit){
        return StatusHandlerRegistry.acquireStatusHandler(leavePermit.getLeavePermitType(),leavePermit.getStatus());
    }
}

  全部的狀態處理類都會保存在StatusHandlerRegistry對象中,該對象負責註冊全部有關請假類型,狀態和狀態處理類的關係,每次都根據請假類型和狀態去獲取StatusHandler。

public class StatusHandlerRegistry {

    private static Map<String,StatusHandler> statusHandlerMap;

    static {
        statusHandlerMap=new ConcurrentHashMap<String, StatusHandler>();
    }

    private StatusHandlerRegistry(){

    }

    private static String getKey(LeavePermitType leavePermitType,Status status){
        return String.format("%s@-@%s",leavePermitType.getType(),status.name());
    }

    /**
     * 註冊狀態處理類
     * @param leavePermitType  請假類型
     * @param status           請假狀態
     * @param statusHandler    狀態處理對象
     */
    public static void registryStatusHandler(LeavePermitType leavePermitType,Status status,StatusHandler statusHandler){
        statusHandlerMap.put(getKey(leavePermitType,status),statusHandler);
    }

    /**
     * 獲取狀態處理類
     * @param leavePermitType  請假類型
     * @param status            請假狀態
     * @return StatusHandler         
     */
    public static StatusHandler acquireStatusHandler(LeavePermitType leavePermitType,Status status){
        return statusHandlerMap.get(getKey(leavePermitType,status));
    }
}

  

因此,在咱們項目啓動中,將請假類型,請假狀態和狀態處理對象StatusHandler註冊到StatusHandlerRegistry中,當LeavePermitHandler 處理類接收到StatusHandlerEngine.post()的假單的時候,能夠根據請假類型和狀態獲取相應的處理類StatusHandler,作相應狀態邏輯的處理,邏輯處理結束,是否繼續狀態機取決於statusHandler的after方法是否調用goNextStatusHandler(leavePermit);在調用goNextStatusHandler(leavePermit)的時候,會去狀態機獲取下一個狀態,StatusHandlerEngine.post(leavePermit)將繼續去獲取處理類statusHandler,這個時候,應爲leavePermit的狀態已經發生變化,因此獲取到的statusHandler已經發生變化。
看一下運行結果:


public static void main(String[] args) {
       //註冊年休假的狀態和對應狀態的處理類StatusHandler。
        registryAnnualPermitStatusHandler();
        //註冊病假的狀態和對應狀態的處理類StatusHandler。
        registryMedicalPermitStatusHandler();

        LeavePermitHandler leavePermitHandler=new LeavePermitHandler();
        //狀態機引擎接受事件處理類
        StatusMachineEngine.addListener(leavePermitHandler);
        //生成假單
        LeavePermit leavePermit=new LeavePermit();
        leavePermit.setLeavePermitType(LeavePermitType.ANNUAL_LEAVE);
        leavePermit.setStatus(Status.PERMIT_SUBMIT);
        leavePermit.setUser("jettyrun");
        //假單交給引擎去執行
        StatusMachineEngine.post(leavePermit);
        System.out.println("----- 分割線 表明假條須要領導審批了,領導給個經過意見,而後狀態機接着走-------");
        leavePermit.setEvent(Event.AGREE);
        StatusMachineEngine.post(leavePermit);
        System.out.println("----- 分割線 表明假條須要ceo審批了,ceo給個經過意見,而後狀態機接着走-------");
        leavePermit.setEvent(Event.AGREE);
        StatusMachineEngine.post(leavePermit);
        System.out.println("--->>>>>>>>>end<<<<<<<<-------");

}


 public static void registryAnnualPermitStatusHandler() {

        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.PERMIT_SUBMIT, new AnnualPermitSubmitStatusHandler());

        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.LEADER_PERMIT_AGREE, new AnnualLeaderAgreeStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.LEADER_PERMIT_DISAGREE, new AnnualLeaderDisAgreeStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.LEADER_PERMIT_MODIFY, new AnnualLeaderPermitModifyStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.LEADER_PERMITING, new AnnualLeaderPermitingStatusHandler());

        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.CEO_PERMIT_AGREE, new AnnualCEOAgreeStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.CEO_PERMIT_DISAGREE, new AnnualCEODisAgreeStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.CEO_PERMIT_MODIFY, new AnnualCEOPermitModifyStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.CEO_PERMITING, new AnnualCEOPermitingStatusHandler());

        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.PERMIT_SUCCESS, new AnnualPermitSuccessStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.PERMIT_FAIL, new AnnualPermitFailStatusHandler());
    }



    public static void registryMedicalPermitStatusHandler() {

        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.PERMIT_SUBMIT, new MedicalPermitSubmitStatusHandler());

        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.LEADER_PERMIT_AGREE, new MedicalLeaderAgreeStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.LEADER_PERMIT_DISAGREE, new MedicalLeaderDisAgreeStatusHandler
                ());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.LEADER_PERMIT_MODIFY, new MedicalLeaderPermitModifyStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.LEADER_PERMITING, new MedicalLeaderPermitingStatusHandler());

        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.HR_PERMIT_AGREE, new MedicalHrAgreeStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.HR_PERMIT_DISAGREE, new MedicalHrDisAgreeStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.HR_PERMIT_MODIFY, new MedicalHrPermitModifyStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.HR_PERMITING, new MedicalHrPermitingStatusHandler());

        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.PERMIT_SUCCESS, new MedicalPermitSuccessStatusHandler());
        StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.PERMIT_FAIL, new MedicalPermitFailStatusHandler());
    }

  執行結果:

user:jettyrun--提交年休假假單--leavePermit status:permitSubmit
user:jettyrun--領導審批年休假中--leavePermit status:leaderPermiting
user:jettyrun--等待領導審批--leavePermit status:leaderPermiting
----- 分割線 表明假條須要領導審批了,領導給個經過意見,而後狀態機接着走-------
user:jettyrun--領導審批年休假中--leavePermit status:leaderPermiting
user:jettyrun--直線領導贊成請年休假--leavePermit status:leaderAgree
user:jettyrun--ceo審批年休假中--leavePermit status:ceoPermiting
user:jettyrun--等待ceo審批--leavePermit status:ceoPermiting
----- 分割線 表明假條須要領導審批了,ceo給個經過意見,而後狀態機接着走-------
user:jettyrun--ceo審批年休假中--leavePermit status:ceoPermiting
user:jettyrun--ceo贊成休年休假--leavePermit status:ceoAgree
user:jettyrun--請年休假假成功--leavePermit status:permitSuccess
--->>>>>>>>>end<<<<<<<<-------


  

能夠看到,當須要領導,CEO審批假單的時候,狀態機可以自動中斷,領導,ceo贊成了該請假請求leavePermit.setEvent(Event.AGREE);狀態機就可以自動運行到最終狀態permitSuccess。
這只是請年休假,再請一個病假
 LeavePermit leavePermit2=new LeavePermit();
        leavePermit2.setLeavePermitType(LeavePermitType.MEDICAL_LEAVE);
        leavePermit2.setStatus(Status.PERMIT_SUBMIT);
        leavePermit2.setUser("jettyrun2");
        StatusMachineEngine.post(leavePermit2);

        System.out.println("----- 分割線 表明假條須要領導審批了,領導給個經過意見,而後狀態機接着走-------");
        leavePermit2.setEvent(Event.AGREE);
        StatusMachineEngine.post(leavePermit2);


        System.out.println("----- 分割線 表明假條須要hr審批了,hr給個經過意見,而後狀態機接着走-------");
        leavePermit2.setEvent(Event.AGREE);
        StatusMachineEngine.post(leavePermit2);
        System.out.println("--->>>>>>>>>end<<<<<<<<-------");

  

user:jettyrun2--病假提交--leavePermit status:permitSubmit-提交假單
user:jettyrun2--領導審批病假中--leavePermit status:leaderPermiting-領導審批中
user:jettyrun2--等待領導病假審批--leavePermit status:leaderPermiting-領導審批中
----- 分割線 表明假條須要領導審批了,領導給個經過意見,而後狀態機接着走-------
user:jettyrun2--領導審批病假中--leavePermit status:leaderPermiting-領導審批中
user:jettyrun2--領導贊成休病假--leavePermit status:leaderAgree-領導贊成
user:jettyrun2--hr審批病假中--leavePermit status:hrPermiting-hr審批中
user:jettyrun2--等待hr審批--leavePermit status:hrPermiting
----- 分割線 表明假條須要hr審批了,hr給個經過意見,而後狀態機接着走-------
user:jettyrun2--hr審批病假中--leavePermit status:hrPermiting-hr審批中
user:jettyrun2--hr贊成休病假--leavePermit status:hrAgree-hr贊成
user:jettyrun2--成功病假審批--leavePermit status:permitSuccess-請假成功
--->>>>>>>>>end<<<<<<<<-------

  

該狀態機的設計思想有一部分借鑑公司的幾個項目,一部分來源於噹噹elastic-job的源碼解讀心得。
源代碼地址請點擊我 github

相關文章
相關標籤/搜索