首先,了解狀態(tài)機(jī)是什么,我們?yōu)槭裁葱枰獱顟B(tài)機(jī)!
舉個(gè)最簡(jiǎn)單例子,請(qǐng)假,作為一個(gè)最底層程序員,每次請(qǐng)假都要領(lǐng)導(dǎo)層層審批,而假有分為很多種,事假,病假,婚假,年休假等等,當(dāng)然選擇請(qǐng)的假不同,審批標(biāo)準(zhǔn)也不同,不同的假單需要走的審批鏈也不一樣,比如年休假,可能只需要領(lǐng)導(dǎo)審批扣掉年休假即可,請(qǐng)病假需要領(lǐng)導(dǎo)審批,領(lǐng)導(dǎo)審批之后,先休假,等休完假回來提交病假的材料,由hr審批之后才能完成整個(gè)請(qǐng)假過程。更有甚者,如果你要修一個(gè)一個(gè)月的長假,就不僅僅是需要直線領(lǐng)導(dǎo)hr審批,可能還需要公司ceo審批 ,審批通過后,才能通過。如下圖:
當(dāng)然,實(shí)際來講,請(qǐng)假的種類和鏈路比這個(gè)要復(fù)雜的多,我們一般會(huì)怎么實(shí)現(xiàn),是否要使用if else了,對(duì)應(yīng)不同的假單,走不同的分支,代碼寫出來就成了一個(gè)非常復(fù)雜的,多級(jí)嵌套的代碼了,后面如何維護(hù)代碼,多了幾種假的種類,是不是又要if else了。如下代碼:
public void requestLeavePermit(String type){
if(type.equals("事假")){
//領(lǐng)導(dǎo)審批->hr審批->ceo審批->完成
}else if(type.equals("病假")){
//領(lǐng)導(dǎo)審批->休假->補(bǔ)充病例->hr審批->完成
}else if(type.equals("年休假")){
//領(lǐng)導(dǎo)審批->hr審批->通過
}else if(type.equals("產(chǎn)假")){
//領(lǐng)導(dǎo)審批->hr審批->通過
}else if(type.equals("調(diào)休假")){
//領(lǐng)導(dǎo)審批->ceo審批->通過
}
}
或者寫成這個(gè)樣子:
public void requestLeavePermit(String type,String userName){
switch (type){
case "事假":
//領(lǐng)導(dǎo)審批->hr審批->ceo審批->完成
break;
case "病假":
//領(lǐng)導(dǎo)審批->休假->補(bǔ)充病例->hr審批->完成
break;
case "年休假":
//領(lǐng)導(dǎo)審批->hr審批->通過
break;
case "產(chǎn)假":
//領(lǐng)導(dǎo)審批->hr審批->通過
break;
case "調(diào)休假":
//領(lǐng)導(dǎo)審批->ceo審批->通過
default:
break;
}
}
if,else嵌套太深,然后每個(gè)if,else又是自己的處理流程,這樣代碼結(jié)構(gòu)會(huì)原來越復(fù)雜,當(dāng)審批鏈發(fā)生變更,這個(gè)時(shí)候會(huì)發(fā)現(xiàn)代碼耦合性太強(qiáng),導(dǎo)致修改起來很麻煩。
如何解決這個(gè)問題,我們不難看到,所有的請(qǐng)假都經(jīng)過了這樣幾個(gè)階段,從請(qǐng)假開始,提交假單,然后領(lǐng)導(dǎo)審批,hr審批,ceo審批,只是不同的是,有些審批流程多了審核人或者是少了審核人,每種假單審核材料有所不同而已。
我們?nèi)绾问褂脿顟B(tài)機(jī)來如何解決代碼耦合性的問題,提高代碼可擴(kuò)展性可讀性。
如果我們把領(lǐng)導(dǎo)審批,hr審批,ceo審批,分別看做一個(gè)動(dòng)作,每個(gè)相應(yīng)都有幾個(gè)狀態(tài),審批通過,不通過,拒絕,重新審核,會(huì)怎么樣?
首先,我們將請(qǐng)假的類型定義成一個(gè)枚舉:
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;
//此處忽略構(gòu)造方法和set/get方法
}
領(lǐng)導(dǎo)審批,hr審批,ceo審批,都有一個(gè)審批意見(通過,拒絕,或者是重修修改假單補(bǔ)充材料等),在這里,相當(dāng)于一個(gè)事件Event,于是,整個(gè)狀態(tài)扭轉(zhuǎn)也可以用一個(gè)枚舉類來表示,審批意見由一個(gè)枚舉類Event來表示。
public enum Event {
AGREE("agree","同意"),
DISSAGREE("disagree","不同意"),
MODIFY("modify","修改"),
;
private String type;
private String memo;
}
因此,一個(gè)假單的狀態(tài)就有很多種,用一個(gè)枚舉代表整個(gè)假單的狀態(tài):
public enum Status {
//提交假單
PERMIT_SUBMIT("permitSubmit","提交假單"),
//領(lǐng)導(dǎo)審批
LEADER_PERMITING("leaderPermiting","領(lǐng)導(dǎo)審批中"),
LEADER_PERMIT_AGREE("leaderAgree","領(lǐng)導(dǎo)同意"),
LEADER_PERMIT_DISAGREE("leaderDisAgree","領(lǐng)導(dǎo)不同意"),
LEADER_PERMIT_MODIFY("leaderModify","領(lǐng)導(dǎo)覺得需要補(bǔ)充材料重修修改"),
//hr審批
HR_PERMITING("hrPermiting","hr審批中"),
HR_PERMIT_AGREE("hrAgree","hr同意"),
HR_PERMIT_DISAGREE("hrDisAgree","hr不同意"),
HR_PERMIT_MODIFY("hrModify","hr覺得需要補(bǔ)充材料重修修改"),
//ceo審批
CEO_PERMITING("ceoPermiting","領(lǐng)導(dǎo)審批中"),
CEO_PERMIT_AGREE("ceoAgree","ceo同意"),
CEO_PERMIT_DISAGREE("ceoDisAgree","ceo不同意"),
CEO_PERMIT_MODIFY("ceoModify","ceo覺得需要補(bǔ)充材料重修修改"),
//最終請(qǐng)假狀態(tài)
PERMIT_SUCCESS("permitSuccess","請(qǐng)假成功"),
PERMIT_FAIL("permitFail","請(qǐng)假失敗")
;
private String status;
private String memo;
private Status(String status,String memo){
this.status=status;
this.memo=memo;
}
}
狀態(tài)定義清楚之后,需要考慮兩個(gè)問題
- 從當(dāng)前狀態(tài)需要能夠跳轉(zhuǎn)到下一個(gè)狀態(tài),比如提交假單之后,要能夠從提交假單狀態(tài)跳轉(zhuǎn)到領(lǐng)導(dǎo)審批狀態(tài)。
- 不同的審批意見要能夠跳轉(zhuǎn)不同的狀態(tài),比如領(lǐng)導(dǎo)審批狀態(tài)跳轉(zhuǎn)審批通過,或者拒絕該審批需要能夠按照Event狀態(tài)跳轉(zhuǎn)不同的狀態(tài)。
這塊功能可以交給狀態(tài)機(jī)StatusMachine去解決,由當(dāng)前狀態(tài)+事件驅(qū)動(dòng)(也就是當(dāng)前請(qǐng)假的狀態(tài)和審批意見)獲取下一個(gè)狀態(tài)。
我們知道,請(qǐng)假的種類不同,所走的流程也不同,相應(yīng)的處理也不同,每種假單都有自己的審批鏈,也對(duì)應(yīng)每種假單有不同的狀態(tài)機(jī),不難設(shè)計(jì)StatusMachine為接口或抽象類。狀態(tài)機(jī)只做一件事情,根據(jù)event(審批意見),跳轉(zhuǎn)下一個(gè)狀態(tài)機(jī)。
public interface StatusMachine {
/**
*@params status 當(dāng)前狀態(tài)
*@params event 審批意見
*@return 下一個(gè)狀態(tài)
**/
public Status getNextStatus(Status status,Event event);
}
這里舉兩個(gè)例子,一個(gè)病假,一個(gè)年休假的實(shí)現(xiàn):
年休假的審批流程:
- 提交假單 PERMIT_SUBMIT
- 領(lǐng)導(dǎo)審批 LEADER_PERMITING
- 等待領(lǐng)導(dǎo)審批
- 領(lǐng)導(dǎo)審批通過/不通過/拒絕
- 領(lǐng)導(dǎo)審批通過 LEADER_PERMIT_AGREE
- ceo審批 CEO_PERMITING
- 等待ceo審批意見
- ceo審批通過/不通過/拒絕
- ceo審批通過 CEO_PERMIT_AGREE
- 請(qǐng)假完成 PERMIT_SUCCESS
因此事假的狀態(tài)機(jī)StatusMachine實(shí)現(xiàn)如下:
public class AnnualLeaveStatusMachine implements StatusMachine{
public Status getNextStatus(Status status,Event event){
switch (status){
case PERMIT_SUBMIT:
//提交假單狀態(tài)無需審批跳轉(zhuǎn)領(lǐng)導(dǎo)審批中狀態(tài)
return Status.LEADER_PERMITING;
case LEADER_PERMITING:
//領(lǐng)導(dǎo)審批需要審批意見 審批意見不用返回不同的狀態(tài)
return getLeaderPermitStatus(event);
case LEADER_PERMIT_AGREE:
//領(lǐng)導(dǎo)同意請(qǐng)假,則跳轉(zhuǎn)ceo審批
return Status.CEO_PERMITING;
case LEADER_PERMIT_DISAGREE:
//領(lǐng)導(dǎo)不同意該假單,則請(qǐng)假失敗
return Status.PERMIT_FAIL;
case LEADER_PERMIT_MODIFY:
return getLeaderPermitStatus(event);
case CEO_PERMITING:
//ceo審批需要審批意見
return getCEOPermitStatus(event);
case CEO_PERMIT_AGREE:
// ceo審批同意 跳轉(zhuǎn)審批通過 請(qǐng)假完成
return Status.PERMIT_SUCCESS;
case CEO_PERMIT_DISAGREE:
//ceo不同意審批 則跳轉(zhuǎn)審批失敗
return Status.PERMIT_FAIL;
case CEO_PERMIT_MODIFY:
return getCEOPermitStatus(event);
default:
throw new RuntimeException("沒有該流程");
}
}
private Status getLeaderPermitStatus(Event event){
switch (event){
case AGREE:
//領(lǐng)導(dǎo)審批通過 返回同意該假單
return Status.LEADER_PERMIT_AGREE;
case DISSAGREE:
//領(lǐng)導(dǎo)不同意 則返回領(lǐng)導(dǎo)拒絕改假單狀態(tài)
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不同意該假單狀態(tài)
return Status.CEO_PERMIT_DISAGREE;
case MODIFY:
return Status.CEO_PERMIT_MODIFY;
default:
throw new RuntimeException("不支持該Event審批意見");
}
}
}
病假的審批流程:
- 提交假單 PERMIT_SUBMIT
- 領(lǐng)導(dǎo)審批 LEADER_PERMITING
- 等待領(lǐng)導(dǎo)審批
- 領(lǐng)導(dǎo)審批通過/不通過/拒絕
- 領(lǐng)導(dǎo)審批通過 LEADER_PERMIT_AGREE
- HR審批 HR_PERMITING
- 等待HR審批意見
- HR審批通過/不通過/拒絕
- HR審批通過 CEO_PERMIT_AGREE
- 請(qǐng)假完成 PERMIT_SUCCESS
根據(jù)該流程不難設(shè)計(jì)出該狀態(tài)機(jī)
public class MedicalLeaveStatusMachine implements StatusMachine{
public Status getNextStatus(Status status,Event event){
switch (status){
case PERMIT_SUBMIT:
//提交假單狀態(tài)直接跳轉(zhuǎn)領(lǐng)導(dǎo)審批中狀態(tài)
return Status.LEADER_PERMITING;
case LEADER_PERMITING:
//領(lǐng)導(dǎo)審批中狀態(tài)需要審批意見再獲取下一個(gè)狀態(tài)
return getLeaderPermitStatus(event);
case LEADER_PERMIT_AGREE:
//領(lǐng)導(dǎo)同意審批該假單 跳轉(zhuǎn)hr審批中狀態(tài)
return Status.HR_PERMITING;
case LEADER_PERMIT_DISAGREE:
//領(lǐng)導(dǎo)不同意則返回請(qǐng)假失敗
return Status.PERMIT_FAIL;
case LEADER_PERMIT_MODIFY:
return getLeaderPermitStatus(event);
case HR_PERMITING:
//hr審批根據(jù)審批意見跳轉(zhuǎn)下一個(gè)狀態(tài)
return getHrPermitStatus(event);
case HR_PERMIT_AGREE:
//hr審批通過跳轉(zhuǎn)審批完成狀態(tài)
return Status.PERMIT_SUCCESS;
case HR_PERMIT_DISAGREE:
// hr審批不同意 返回請(qǐng)假失敗
return Status.PERMIT_FAIL;
case HR_PERMIT_MODIFY:
return getHrPermitStatus(event);
default:
throw new RuntimeException("沒有該流程");
}
}
private Status getLeaderPermitStatus(Event event){
switch (event){
case AGREE:
//領(lǐng)導(dǎo)同意該假單,則返回領(lǐng)導(dǎo)審批通過
return Status.LEADER_PERMIT_AGREE;
case DISSAGREE:
//領(lǐng)導(dǎo)不同意該假單 則返回領(lǐng)導(dǎo)審批不通過
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同意狀態(tài)
return Status.HR_PERMIT_AGREE;
case DISSAGREE:
//hr審批不同意該假單,則返回hr不同意狀態(tài)
return Status.HR_PERMIT_DISAGREE;
case MODIFY:
return Status.HR_PERMIT_MODIFY;
default:
throw new RuntimeException("不支持該Event審批意見");
}
}
}
對(duì)于請(qǐng)假的員工來講,只知道提交了一個(gè)假單,并不會(huì)關(guān)心到底該流程怎么走,所以在設(shè)計(jì)的時(shí)候,需要根據(jù)請(qǐng)假類型能夠自動(dòng)匹配狀態(tài)機(jī),這里可以用靜態(tài)工廠去實(shí)現(xiàn)。
public class StatusMachineFactory {
private StatusMachineFactory(){
}
/**
* 根據(jù)狀態(tài)獲取狀態(tài)機(jī)
* @param leavePermitType
* @return 對(duì)應(yīng)請(qǐng)假類型的狀態(tài)機(jī)
*/
public static StatusMachine getStatusMachine(LeavePermitType leavePermitType){
switch (leavePermitType){
case MEDICAL_LEAVE:
return new MedicalLeaveStatusMachine();
case ANNUAL_LEAVE:
return new AnnualLeaveStatusMachine();
default:
throw new RuntimeException("未知類型");
}
}
}
狀態(tài)機(jī)設(shè)計(jì)好之后,每個(gè)狀態(tài)都應(yīng)該對(duì)應(yīng)有該狀態(tài)的處理類,且需要統(tǒng)一管理該狀態(tài)和處理類的關(guān)系。
以年休假為例:提交假單->領(lǐng)導(dǎo)審批4個(gè)狀態(tài)->ceo審批4個(gè)狀態(tài)->請(qǐng)假完成/失敗2個(gè)狀態(tài)。
總計(jì)需要11個(gè)狀態(tài)處理對(duì)象去處理該狀態(tài)。
該狀態(tài)處理類需要具備哪些能力:
- 處理該狀態(tài)的業(yè)務(wù)
- 能夠決定要不要扭轉(zhuǎn)該狀態(tài)機(jī)接著往下走(提交假單狀態(tài)處理結(jié)束要能夠自動(dòng)運(yùn)行到領(lǐng)導(dǎo)審批狀態(tài),領(lǐng)導(dǎo)審批狀態(tài)不能接著扭轉(zhuǎn)到下一個(gè)狀態(tài),需要等待領(lǐng)導(dǎo)的審批意見才可繼續(xù)往下走)
不難設(shè)計(jì),先抽象出一個(gè)StatusHandler接口或父類,每個(gè)狀態(tài)的處理類去實(shí)現(xiàn)該接口或繼承該父類,在statusHandler中,有三個(gè)方法,before,dohandler,after,after主要負(fù)責(zé)扭轉(zhuǎn)狀態(tài)機(jī),獲取下一個(gè)狀態(tài)的處理類處理下一個(gè)狀態(tài)的事件。如果狀態(tài)到達(dá)某一個(gè)狀態(tài)不需要往下繼續(xù)執(zhí)行,則重寫after方法即可中斷狀態(tài)機(jī),dohandler主要負(fù)責(zé)做業(yè)務(wù)處理。
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){
//去下一個(gè)狀態(tài)的處理對(duì)象處理
goNextStatusHandler(leavePermit);
}
protected void goNextStatusHandler(LeavePermit leavePermit){
//獲取下一個(gè)狀態(tài)
leavePermit.setStatus(StatusMachineFactory.getStatusMachine(leavePermit.getLeavePermitType()).getNextStatus(leavePermit.getStatus(),leavePermit.getEvent()));
//狀態(tài)機(jī)引擎驅(qū)動(dòng)假單處理
StatusMachineEngine.post(leavePermit);
}
在看一下具體的狀態(tài)處理類實(shí)現(xiàn),11個(gè)狀態(tài)對(duì)應(yīng)11個(gè)處理類,這里列舉出部分
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--領(lǐng)導(dǎo)審批年休假中--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus()));
}
@Override
protected void after(LeavePermit leavePermit){
if(leavePermit.getEvent()==null){
//還未審批,狀態(tài)機(jī)結(jié)束,等待審批意見
System.out.println(String.format("user:%s--等待領(lǐng)導(dǎo)審批--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--直線領(lǐng)導(dǎo)同意請(qǐng)年休假--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--直線領(lǐng)導(dǎo)同意請(qǐng)年休假--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){
//還未審批,狀態(tài)機(jī)結(jié)束,等待審批意見
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--請(qǐng)年休假假成功--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus(),leavePermit.getStatus().getMemo()));
}
@Override
protected void after(LeavePermit leavePermit){
}
}
關(guān)于假單的請(qǐng)求,都會(huì)由StatusMachineEngine.post(LeavePermit)去處理,這里是如何做到按照請(qǐng)假類型,和狀態(tài)找到對(duì)應(yīng)的statusHandler的?
這里是使用eventbus去實(shí)現(xiàn)(基于消息訂閱發(fā)布模式實(shí)現(xiàn))
public class StatusMachineEngine {
private static EventBus eventBus;
static{
eventBus = new EventBus();
}
/**
* 發(fā)布一條假單
* @param leavePermit
*/
public static void post(LeavePermit leavePermit) {
eventBus.post(leavePermit);
}
/**
* 假單處理類
* @param statusLeavePermitHandler
*/
public static void addListener(LeavePermitHandler statusLeavePermitHandler) {
eventBus.register(statusLeavePermitHandler);
}
}
所有假單的處理都會(huì)交給LeavePermitHandler去處理,這個(gè)對(duì)象里按照請(qǐng)假類型和請(qǐng)假狀態(tài)做路由,選擇不同的statusHandler處理業(yè)務(wù)邏輯。
public class LeavePermitHandler {
//處理假單 注解代表可以接受到StatusMachineEngine發(fā)布的假單
@Subscribe
@AllowConcurrentEvents
public void handle(LeavePermit leavePermit){
//獲取到狀態(tài)處理類,然后去處理 handler為StatusHandler的入口
getStatusHandler(leavePermit).handle(leavePermit);
}
/**
* 根據(jù)假單獲取StatusHandler 狀態(tài)處理對(duì)象
* @param leavePermit
* @return
*/
public static StatusHandler getStatusHandler(LeavePermit leavePermit){
return StatusHandlerRegistry.acquireStatusHandler(leavePermit.getLeavePermitType(),leavePermit.getStatus());
}
}
所有的狀態(tài)處理類都會(huì)保存在StatusHandlerRegistry對(duì)象中,該對(duì)象負(fù)責(zé)注冊(cè)所有有關(guān)請(qǐng)假類型,狀態(tài)和狀態(tài)處理類的關(guān)系,每次都根據(jù)請(qǐng)假類型和狀態(tài)去獲取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());
}
/**
* 注冊(cè)狀態(tài)處理類
* @param leavePermitType 請(qǐng)假類型
* @param status 請(qǐng)假狀態(tài)
* @param statusHandler 狀態(tài)處理對(duì)象
*/
public static void registryStatusHandler(LeavePermitType leavePermitType,Status status,StatusHandler statusHandler){
statusHandlerMap.put(getKey(leavePermitType,status),statusHandler);
}
/**
* 獲取狀態(tài)處理類
* @param leavePermitType 請(qǐng)假類型
* @param status 請(qǐng)假狀態(tài)
* @return StatusHandler
*/
public static StatusHandler acquireStatusHandler(LeavePermitType leavePermitType,Status status){
return statusHandlerMap.get(getKey(leavePermitType,status));
}
}
所以,在我們項(xiàng)目啟動(dòng)中,將請(qǐng)假類型,請(qǐng)假狀態(tài)和狀態(tài)處理對(duì)象StatusHandler注冊(cè)到StatusHandlerRegistry中,當(dāng)LeavePermitHandler 處理類接收到StatusHandlerEngine.post()的假單的時(shí)候,可以根據(jù)請(qǐng)假類型和狀態(tài)獲取相應(yīng)的處理類StatusHandler,做相應(yīng)狀態(tài)邏輯的處理,邏輯處理結(jié)束,是否繼續(xù)狀態(tài)機(jī)取決于statusHandler的after方法是否調(diào)用goNextStatusHandler(leavePermit);在調(diào)用goNextStatusHandler(leavePermit)的時(shí)候,會(huì)去狀態(tài)機(jī)獲取下一個(gè)狀態(tài),StatusHandlerEngine.post(leavePermit)將繼續(xù)去獲取處理類statusHandler,這個(gè)時(shí)候,應(yīng)為leavePermit的狀態(tài)已經(jīng)發(fā)生變化,所以獲取到的statusHandler已經(jīng)發(fā)生變化。
看一下運(yùn)行結(jié)果:
public static void main(String[] args) {
//注冊(cè)年休假的狀態(tài)和對(duì)應(yīng)狀態(tài)的處理類StatusHandler。
registryAnnualPermitStatusHandler();
//注冊(cè)病假的狀態(tài)和對(duì)應(yīng)狀態(tài)的處理類StatusHandler。
registryMedicalPermitStatusHandler();
LeavePermitHandler leavePermitHandler=new LeavePermitHandler();
//狀態(tài)機(jī)引擎接受事件處理類
StatusMachineEngine.addListener(leavePermitHandler);
//生成假單
LeavePermit leavePermit=new LeavePermit();
leavePermit.setLeavePermitType(LeavePermitType.ANNUAL_LEAVE);
leavePermit.setStatus(Status.PERMIT_SUBMIT);
leavePermit.setUser("jettyrun");
//假單交給引擎去執(zhí)行
StatusMachineEngine.post(leavePermit);
System.out.println("----- 分割線 代表假條需要領(lǐng)導(dǎo)審批了,領(lǐng)導(dǎo)給個(gè)通過意見,然后狀態(tài)機(jī)接著走-------");
leavePermit.setEvent(Event.AGREE);
StatusMachineEngine.post(leavePermit);
System.out.println("----- 分割線 代表假條需要ceo審批了,ceo給個(gè)通過意見,然后狀態(tài)機(jī)接著走-------");
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());
}
執(zhí)行結(jié)果:
user:jettyrun--提交年休假假單--leavePermit status:permitSubmit
user:jettyrun--領(lǐng)導(dǎo)審批年休假中--leavePermit status:leaderPermiting
user:jettyrun--等待領(lǐng)導(dǎo)審批--leavePermit status:leaderPermiting
----- 分割線 代表假條需要領(lǐng)導(dǎo)審批了,領(lǐng)導(dǎo)給個(gè)通過意見,然后狀態(tài)機(jī)接著走-------
user:jettyrun--領(lǐng)導(dǎo)審批年休假中--leavePermit status:leaderPermiting
user:jettyrun--直線領(lǐng)導(dǎo)同意請(qǐng)年休假--leavePermit status:leaderAgree
user:jettyrun--ceo審批年休假中--leavePermit status:ceoPermiting
user:jettyrun--等待ceo審批--leavePermit status:ceoPermiting
----- 分割線 代表假條需要領(lǐng)導(dǎo)審批了,ceo給個(gè)通過意見,然后狀態(tài)機(jī)接著走-------
user:jettyrun--ceo審批年休假中--leavePermit status:ceoPermiting
user:jettyrun--ceo同意休年休假--leavePermit status:ceoAgree
user:jettyrun--請(qǐng)年休假假成功--leavePermit status:permitSuccess
--->>>>>>>>>end<<<<<<<<-------
可以看到,當(dāng)需要領(lǐng)導(dǎo),CEO審批假單的時(shí)候,狀態(tài)機(jī)能夠自動(dòng)中斷,領(lǐng)導(dǎo),ceo同意了該請(qǐng)假請(qǐng)求leavePermit.setEvent(Event.AGREE);狀態(tài)機(jī)就能夠自動(dòng)運(yùn)行到最終狀態(tài)permitSuccess。
這只是請(qǐng)年休假,再請(qǐng)一個(gè)病假
LeavePermit leavePermit2=new LeavePermit();
leavePermit2.setLeavePermitType(LeavePermitType.MEDICAL_LEAVE);
leavePermit2.setStatus(Status.PERMIT_SUBMIT);
leavePermit2.setUser("jettyrun2");
StatusMachineEngine.post(leavePermit2);
System.out.println("----- 分割線 代表假條需要領(lǐng)導(dǎo)審批了,領(lǐng)導(dǎo)給個(gè)通過意見,然后狀態(tài)機(jī)接著走-------");
leavePermit2.setEvent(Event.AGREE);
StatusMachineEngine.post(leavePermit2);
System.out.println("----- 分割線 代表假條需要hr審批了,hr給個(gè)通過意見,然后狀態(tài)機(jī)接著走-------");
leavePermit2.setEvent(Event.AGREE);
StatusMachineEngine.post(leavePermit2);
System.out.println("--->>>>>>>>>end<<<<<<<<-------");
user:jettyrun2--病假提交--leavePermit status:permitSubmit-提交假單
user:jettyrun2--領(lǐng)導(dǎo)審批病假中--leavePermit status:leaderPermiting-領(lǐng)導(dǎo)審批中
user:jettyrun2--等待領(lǐng)導(dǎo)病假審批--leavePermit status:leaderPermiting-領(lǐng)導(dǎo)審批中
----- 分割線 代表假條需要領(lǐng)導(dǎo)審批了,領(lǐng)導(dǎo)給個(gè)通過意見,然后狀態(tài)機(jī)接著走-------
user:jettyrun2--領(lǐng)導(dǎo)審批病假中--leavePermit status:leaderPermiting-領(lǐng)導(dǎo)審批中
user:jettyrun2--領(lǐng)導(dǎo)同意休病假--leavePermit status:leaderAgree-領(lǐng)導(dǎo)同意
user:jettyrun2--hr審批病假中--leavePermit status:hrPermiting-hr審批中
user:jettyrun2--等待hr審批--leavePermit status:hrPermiting
----- 分割線 代表假條需要hr審批了,hr給個(gè)通過意見,然后狀態(tài)機(jī)接著走-------
user:jettyrun2--hr審批病假中--leavePermit status:hrPermiting-hr審批中
user:jettyrun2--hr同意休病假--leavePermit status:hrAgree-hr同意
user:jettyrun2--成功病假審批--leavePermit status:permitSuccess-請(qǐng)假成功
--->>>>>>>>>end<<<<<<<<-------
該狀態(tài)機(jī)的設(shè)計(jì)思想有一部分借鑒公司的幾個(gè)項(xiàng)目,一部分來源于當(dāng)當(dāng)elastic-job的源碼解讀心得。
源代碼地址請(qǐng)點(diǎn)擊我 github
fyi