摘自:https://www.jianshu.com/p/8def04b34b3c
首先,了解狀態機是什么,我們為什么需要狀態機!
舉個最簡單例子,請假,作為一個最底層程序員,每次請假都要領導層層審批,而假有分為很多種,事假,病假,婚假,年休假等等,當然選擇請的假不同,審批標准也不同,不同的假單需要走的審批鏈也不一樣,比如年休假,可能只需要領導審批扣掉年休假即可,請病假需要領導審批,領導審批之后,先休假,等休完假回來提交病假的材料,由hr審批之后才能完成整個請假過程。更有甚者,如果你要修一個一個月的長假,就不僅僅是需要直線領導hr審批,可能還需要公司ceo審批 ,審批通過后,才能通過。如下圖:
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;
}
}
如何解決這個問題,我們不難看到,所有的請假都經過了這樣幾個階段,從請假開始,提交假單,然后領導審批,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來表示。
public enum Event {
AGREE("agree","同意"),
DISSAGREE("disagree","不同意"),
MODIFY("modify","修改"),
;
private String type;
private String memo;
}
因此,一個假單的狀態就有很多種,用一個枚舉代表整個假單的狀態:
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;
}
}
狀態定義清楚之后,需要考慮兩個問題
- 從當前狀態需要能夠跳轉到下一個狀態,比如提交假單之后,要能夠從提交假單狀態跳轉到領導審批狀態。
- 不同的審批意見要能夠跳轉不同的狀態,比如領導審批狀態跳轉審批通過,或者拒絕該審批需要能夠按照Event狀態跳轉不同的狀態。
這塊功能可以交給狀態機StatusMachine去解決,由當前狀態+事件驅動(也就是當前請假的狀態和審批意見)獲取下一個狀態。
我們知道,請假的種類不同,所走的流程也不同,相應的處理也不同,每種假單都有自己的審批鏈,也對應每種假單有不同的狀態機,不難設計StatusMachine為接口或抽象類。狀態機只做一件事情,根據event(審批意見),跳轉下一個狀態機。
public interface StatusMachine {
/**
*@params status 當前狀態
*@params event 審批意見
*@return 下一個狀態
**/
public Status getNextStatus(Status status,Event event);
}
這里舉兩個例子,一個病假,一個年休假的實現:
年休假的審批流程:
- 提交假單 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));
}
}
看一下運行結果:
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
