EventBus

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

首先,了解状态机是什么,我们为什么需要状态机!
举个最简单例子,请假,作为一个最底层程序员,每次请假都要领导层层审批,而假有分为很多种,事假,病假,婚假,年休假等等,当然选择请的假不同,审批标准也不同,不同的假单需要走的审批链也不一样,比如年休假,可能只需要领导审批扣掉年休假即可,请病假需要领导审批,领导审批之后,先休假,等休完假回来提交病假的材料,由hr审批之后才能完成整个请假过程。更有甚者,如果你要修一个一个月的长假,就不仅仅是需要直线领导hr审批,可能还需要公司ceo审批 ,审批通过后,才能通过。如下图:

当然,实际来讲,请假的种类和链路比这个要复杂的多,我们一般会怎么实现,是否要使用if else了,对应不同的假单,走不同的分支,代码写出来就成了一个非常复杂的,多级嵌套的代码了,后面如何维护代码,多了几种假的种类,是不是又要if else了。如下代码:

1public void requestLeavePermit(String type){ 2 if(type.equals("事假")){ 3 //领导审批->hr审批->ceo审批->完成 4 }else if(type.equals("病假")){ 5 //领导审批->休假->补充病例->hr审批->完成 6 }else if(type.equals("年休假")){ 7 //领导审批->hr审批->通过 8 }else if(type.equals("产假")){ 9 //领导审批->hr审批->通过 10 }else if(type.equals("调休假")){ 11 //领导审批->ceo审批->通过 12 } 13 }

  或者写成这个样子:

1public void requestLeavePermit(String type,String userName){ 2 switch (type){ 3 case "事假": 4 //领导审批->hr审批->ceo审批->完成 5 break; 6 case "病假": 7 //领导审批->休假->补充病例->hr审批->完成 8 break; 9 case "年休假": 10 //领导审批->hr审批->通过 11 break; 12 case "产假": 13 //领导审批->hr审批->通过 14 break; 15 case "调休假": 16 //领导审批->ceo审批->通过 17 default: 18 break; 19 } 20 }

if,else嵌套太深,然后每个if,else又是自己的处理流程,这样代码结构会原来越复杂,当审批链发生变更,这个时候会发现代码耦合性太强,导致修改起来很麻烦。
如何解决这个问题,我们不难看到,所有的请假都经过了这样几个阶段,从请假开始,提交假单,然后领导审批,hr审批,ceo审批,只是不同的是,有些审批流程多了审核人或者是少了审核人,每种假单审核材料有所不同而已。
我们如何使用状态机来如何解决代码耦合性的问题,提高代码可扩展性可读性
如果我们把领导审批,hr审批,ceo审批,分别看做一个动作,每个相应都有几个状态,审批通过,不通过,拒绝,重新审核,会怎么样?

首先,我们将请假的类型定义成一个枚举:

1public enum LeavePermitEnum { 2 3 ANNUAL_LEAVE("annual_leave","年休假 "), 4 CASUAL_LEAVE("casual_leave","事假"), 5 MEDICAL_LEAVE("medical_leave","病假"), 6 MARRIAGE_LEAVE("marriage_leave","婚假"),; 7 8 private String type; 9 private String memo; 10 //此处忽略构造方法和set/get方法 11}

领导审批,hr审批,ceo审批,都有一个审批意见(通过,拒绝,或者是重修修改假单补充材料等),在这里,相当于一个事件Event,于是,整个状态扭转也可以用一个枚举类来表示,审批意见由一个枚举类Event来表示。

1public enum Event { 2 3 AGREE("agree","同意"), 4 DISSAGREE("disagree","不同意"), 5 MODIFY("modify","修改"), 6 ; 7 private String type; 8 private String memo; 9}

  因此,一个假单的状态就有很多种,用一个枚举代表整个假单的状态:

1public enum Status { 2 //提交假单 3 PERMIT_SUBMIT("permitSubmit","提交假单"), 4 //领导审批 5 LEADER_PERMITING("leaderPermiting","领导审批中"), 6 LEADER_PERMIT_AGREE("leaderAgree","领导同意"), 7 LEADER_PERMIT_DISAGREE("leaderDisAgree","领导不同意"), 8 LEADER_PERMIT_MODIFY("leaderModify","领导觉得需要补充材料重修修改"), 9 10 //hr审批 11 HR_PERMITING("hrPermiting","hr审批中"), 12 HR_PERMIT_AGREE("hrAgree","hr同意"), 13 HR_PERMIT_DISAGREE("hrDisAgree","hr不同意"), 14 HR_PERMIT_MODIFY("hrModify","hr觉得需要补充材料重修修改"), 15 //ceo审批 16 CEO_PERMITING("ceoPermiting","领导审批中"), 17 CEO_PERMIT_AGREE("ceoAgree","ceo同意"), 18 CEO_PERMIT_DISAGREE("ceoDisAgree","ceo不同意"), 19 CEO_PERMIT_MODIFY("ceoModify","ceo觉得需要补充材料重修修改"), 20 21 //最终请假状态 22 PERMIT_SUCCESS("permitSuccess","请假成功"), 23 PERMIT_FAIL("permitFail","请假失败") 24 ; 25 26 private String status; 27 private String memo; 28 29 private Status(String status,String memo){ 30 this.status=status; 31 this.memo=memo; 32 } 33}

状态定义清楚之后,需要考虑两个问题

  • 从当前状态需要能够跳转到下一个状态,比如提交假单之后,要能够从提交假单状态跳转到领导审批状态。
  • 不同的审批意见要能够跳转不同的状态,比如领导审批状态跳转审批通过,或者拒绝该审批需要能够按照Event状态跳转不同的状态。

这块功能可以交给状态机StatusMachine去解决,由当前状态+事件驱动(也就是当前请假的状态和审批意见)获取下一个状态。

我们知道,请假的种类不同,所走的流程也不同,相应的处理也不同,每种假单都有自己的审批链,也对应每种假单有不同的状态机,不难设计StatusMachine为接口或抽象类。状态机只做一件事情,根据event(审批意见),跳转下一个状态机。

1public interface StatusMachine { 2 /** 3 *@params status 当前状态 4 *@params event 审批意见 5 *@return 下一个状态 6 **/ 7 public Status getNextStatus(Status status,Event event); 8}

这里举两个例子,一个病假,一个年休假的实现:

年休假的审批流程:

  • 提交假单 PERMIT_SUBMIT
  • 领导审批 LEADER_PERMITING
  • 等待领导审批
  • 领导审批通过/不通过/拒绝
  • 领导审批通过 LEADER_PERMIT_AGREE
  • ceo审批 CEO_PERMITING
  • 等待ceo审批意见
  • ceo审批通过/不通过/拒绝
  • ceo审批通过 CEO_PERMIT_AGREE
  • 请假完成 PERMIT_SUCCESS

因此事假的状态机StatusMachine实现如下:

1public class AnnualLeaveStatusMachine implements StatusMachine{ 2 3 4 public Status getNextStatus(Status status,Event event){ 5 switch (status){ 6 7 case PERMIT_SUBMIT: 8 //提交假单状态无需审批跳转领导审批中状态 9 return Status.LEADER_PERMITING; 10 11 case LEADER_PERMITING: 12 //领导审批需要审批意见 审批意见不用返回不同的状态 13 return getLeaderPermitStatus(event); 14 case LEADER_PERMIT_AGREE: 15 //领导同意请假,则跳转ceo审批 16 return Status.CEO_PERMITING; 17 case LEADER_PERMIT_DISAGREE: 18 //领导不同意该假单,则请假失败 19 return Status.PERMIT_FAIL; 20 case LEADER_PERMIT_MODIFY: 21 return getLeaderPermitStatus(event); 22 23 case CEO_PERMITING: 24 //ceo审批需要审批意见 25 return getCEOPermitStatus(event); 26 case CEO_PERMIT_AGREE: 27 // ceo审批同意 跳转审批通过 请假完成 28 return Status.PERMIT_SUCCESS; 29 30 case CEO_PERMIT_DISAGREE: 31 //ceo不同意审批 则跳转审批失败 32 return Status.PERMIT_FAIL; 33 case CEO_PERMIT_MODIFY: 34 return getCEOPermitStatus(event); 35 36 default: 37 throw new RuntimeException("没有该流程"); 38 } 39 } 40 41 42 43 private Status getLeaderPermitStatus(Event event){ 44 switch (event){ 45 case AGREE: 46 //领导审批通过 返回同意该假单 47 return Status.LEADER_PERMIT_AGREE; 48 case DISSAGREE: 49 //领导不同意 则返回领导拒绝改假单状态 50 return Status.LEADER_PERMIT_DISAGREE; 51 case MODIFY: 52 return Status.LEADER_PERMIT_MODIFY; 53 default: 54 throw new RuntimeException("不支持该Event审批意见"); 55 } 56 } 57 58 59 private Status getCEOPermitStatus(Event event){ 60 switch (event){ 61 case AGREE: 62 //ceo审批通过 则返回ceo同意该假单 63 return Status.CEO_PERMIT_AGREE; 64 case DISSAGREE: 65 // ceo审批不通过 则返回ceo不同意该假单状态 66 return Status.CEO_PERMIT_DISAGREE; 67 case MODIFY: 68 return Status.CEO_PERMIT_MODIFY; 69 default: 70 throw new RuntimeException("不支持该Event审批意见"); 71 } 72 } 73}

病假的审批流程:

  • 提交假单 PERMIT_SUBMIT

  • 领导审批 LEADER_PERMITING

  • 等待领导审批

  • 领导审批通过/不通过/拒绝

  • 领导审批通过 LEADER_PERMIT_AGREE

  • HR审批 HR_PERMITING

  • 等待HR审批意见

  • HR审批通过/不通过/拒绝

  • HR审批通过 CEO_PERMIT_AGREE

  • 请假完成 PERMIT_SUCCESS
    根据该流程不难设计出该状态机

    public class MedicalLeaveStatusMachine implements StatusMachine{

    1public Status getNextStatus(Status status,Event event){ 2 switch (status){ 3 case PERMIT_SUBMIT: 4 //提交假单状态直接跳转领导审批中状态 5 return Status.LEADER_PERMITING; 6 7 8 case LEADER_PERMITING: 9 //领导审批中状态需要审批意见再获取下一个状态 10 return getLeaderPermitStatus(event); 11 case LEADER_PERMIT_AGREE: 12 //领导同意审批该假单 跳转hr审批中状态 13 return Status.HR_PERMITING; 14 case LEADER_PERMIT_DISAGREE: 15 //领导不同意则返回请假失败 16 return Status.PERMIT_FAIL; 17 case LEADER_PERMIT_MODIFY: 18 return getLeaderPermitStatus(event); 19 20 case HR_PERMITING: 21 //hr审批根据审批意见跳转下一个状态 22 return getHrPermitStatus(event); 23 case HR_PERMIT_AGREE: 24 //hr审批通过跳转审批完成状态 25 return Status.PERMIT_SUCCESS; 26 case HR_PERMIT_DISAGREE: 27 // hr审批不同意 返回请假失败 28 return Status.PERMIT_FAIL; 29 case HR_PERMIT_MODIFY: 30 return getHrPermitStatus(event); 31 32 default: 33 throw new RuntimeException("没有该流程"); 34 } 35} 36private Status getLeaderPermitStatus(Event event){ 37 switch (event){ 38 case AGREE: 39 //领导同意该假单,则返回领导审批通过 40 return Status.LEADER_PERMIT_AGREE; 41 case DISSAGREE: 42 //领导不同意该假单 则返回领导审批不通过 43 return Status.LEADER_PERMIT_DISAGREE; 44 case MODIFY: 45 return Status.LEADER_PERMIT_MODIFY; 46 default: 47 throw new RuntimeException("不支持该Event审批意见"); 48 } 49} 50private Status getHrPermitStatus(Event event){ 51 switch (event){ 52 case AGREE: 53 //hr审批同意该假单,则返回hr同意状态 54 return Status.HR_PERMIT_AGREE; 55 case DISSAGREE: 56 //hr审批不同意该假单,则返回hr不同意状态 57 return Status.HR_PERMIT_DISAGREE; 58 case MODIFY: 59 return Status.HR_PERMIT_MODIFY; 60 default: 61 throw new RuntimeException("不支持该Event审批意见"); 62 } 63}

    }

  对于请假的员工来讲,只知道提交了一个假单,并不会关心到底该流程怎么走,所以在设计的时候,需要根据请假类型能够自动匹配状态机,这里可以用静态工厂去实现。

1public class StatusMachineFactory { 2 3 private StatusMachineFactory(){ 4 5 } 6 7 /** 8 * 根据状态获取状态机 9 * @param leavePermitType 10 * @return 对应请假类型的状态机 11 */ 12 public static StatusMachine getStatusMachine(LeavePermitType leavePermitType){ 13 switch (leavePermitType){ 14 case MEDICAL_LEAVE: 15 return new MedicalLeaveStatusMachine(); 16 case ANNUAL_LEAVE: 17 return new AnnualLeaveStatusMachine(); 18 default: 19 throw new RuntimeException("未知类型"); 20 } 21 } 22}

状态机设计好之后,每个状态都应该对应有该状态的处理类,且需要统一管理该状态和处理类的关系。
以年休假为例:提交假单->领导审批4个状态->ceo审批4个状态->请假完成/失败2个状态。

总计需要11个状态处理对象去处理该状态。

该状态处理类需要具备哪些能力

  • 处理该状态的业务
  • 能够决定要不要扭转该状态机接着往下走(提交假单状态处理结束要能够自动运行到领导审批状态,领导审批状态不能接着扭转到下一个状态,需要等待领导的审批意见才可继续往下走)

不难设计,先抽象出一个StatusHandler接口或父类,每个状态的处理类去实现该接口或继承该父类,在statusHandler中,有三个方法,before,dohandler,after,after主要负责扭转状态机,获取下一个状态的处理类处理下一个状态的事件。如果状态到达某一个状态不需要往下继续执行,则重写after方法即可中断状态机,dohandler主要负责做业务处理。

1public interface AbstractStatusHandler { 2 public void handle(LeavePermit leavePermit); 3} 4 5public abstract class StatusHandler implements AbstractStatusHandler{ 6 7 protected void before(LeavePermit leavePermit){ 8 } 9 10 11 public void handle(LeavePermit leavePermit){ 12 before(leavePermit); 13 doHandler(leavePermit); 14 after(leavePermit); 15 } 16 protected abstract void doHandler(LeavePermit leavePermit); 17 18 protected void after(LeavePermit leavePermit){ 19 //去下一个状态的处理对象处理 20 goNextStatusHandler(leavePermit); 21 } 22 23 protected void goNextStatusHandler(LeavePermit leavePermit){ 24 //获取下一个状态 25 leavePermit.setStatus(StatusMachineFactory.getStatusMachine(leavePermit.getLeavePermitType()).getNextStatus(leavePermit.getStatus(),leavePermit.getEvent())); 26 //状态机引擎驱动假单处理 27 StatusMachineEngine.post(leavePermit); 28 }

  在看一下具体的状态处理类实现,11个状态对应11个处理类,这里列举出部分

1public class AnnualPermitSubmitStatusHandler extends StatusHandler{ 2 3 protected void doHandler(LeavePermit leavePermit){ 4 System.out.println(String.format("user:%s--提交年休假假单--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus())); 5 } 6 7} 8 9public class AnnualLeaderPermitingStatusHandler extends StatusHandler{ 10 11 protected void doHandler(LeavePermit leavePermit){ 12 System.out.println(String.format("user:%s--领导审批年休假中--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus())); 13 } 14 @Override 15 protected void after(LeavePermit leavePermit){ 16 if(leavePermit.getEvent()==null){ 17 //还未审批,状态机结束,等待审批意见 18 System.out.println(String.format("user:%s--等待领导审批--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus())); 19 return; 20 } 21 super.goNextStatusHandler(leavePermit); 22 } 23} 24 25public class AnnualLeaderAgreeStatusHandler extends StatusHandler{ 26 27 protected void doHandler(LeavePermit leavePermit){ 28 System.out.println(String.format("user:%s--直线领导同意请年休假--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus())); 29 } 30 31} 32public class AnnualLeaderAgreeStatusHandler extends StatusHandler{ 33 34 protected void doHandler(LeavePermit leavePermit){ 35 leavePermit.setEvent(null); 36 System.out.println(String.format("user:%s--直线领导同意请年休假--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus())); 37 } 38 39} 40 41public class AnnualCEOPermitingStatusHandler extends StatusHandler{ 42 43 44 protected void doHandler(LeavePermit leavePermit){ 45 System.out.println(String.format("user:%s--ceo审批年休假中--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus())); 46 47 } 48 49 protected void after(LeavePermit leavePermit){ 50 if(leavePermit.getEvent()==null){ 51 //还未审批,状态机结束,等待审批意见 52 System.out.println(String.format("user:%s--等待ceo审批--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus())); 53 return; 54 } 55 goNextStatusHandler(leavePermit); 56 } 57 58} 59public class AnnualCEOAgreeStatusHandler extends StatusHandler{ 60 61 protected void doHandler(LeavePermit leavePermit){ 62 System.out.println(String.format("user:%s--ceo同意休年休假--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus())); 63 } 64 65} 66 67public class AnnualPermitSuccessStatusHandler extends StatusHandler{ 68 69 @Override 70 protected void doHandler(LeavePermit leavePermit){ 71 System.out.println(String.format("user:%s--请年休假假成功--leavePermit status:%s",leavePermit.getUser(),leavePermit.getStatus().getStatus(),leavePermit.getStatus().getMemo())); 72 } 73 @Override 74 protected void after(LeavePermit leavePermit){ 75 } 76}

  关于假单的请求,都会由StatusMachineEngine.post(LeavePermit)去处理,这里是如何做到按照请假类型,和状态找到对应的statusHandler的?
这里是使用eventbus去实现(基于消息订阅发布模式实现)

1public class StatusMachineEngine { 2 3 private static EventBus eventBus; 4 static{ 5 eventBus = new EventBus(); 6 } 7 8 /** 9 * 发布一条假单 10 * @param leavePermit 11 */ 12 public static void post(LeavePermit leavePermit) { 13 eventBus.post(leavePermit); 14 } 15 16 /** 17 * 假单处理类 18 * @param statusLeavePermitHandler 19 */ 20 public static void addListener(LeavePermitHandler statusLeavePermitHandler) { 21 eventBus.register(statusLeavePermitHandler); 22 } 23}

  所有假单的处理都会交给LeavePermitHandler去处理,这个对象里按照请假类型和请假状态做路由,选择不同的statusHandler处理业务逻辑。

1public class LeavePermitHandler { 2 3 //处理假单 注解代表可以接受到StatusMachineEngine发布的假单 4 @Subscribe 5 @AllowConcurrentEvents 6 public void handle(LeavePermit leavePermit){ 7 //获取到状态处理类,然后去处理 handler为StatusHandler的入口 8 getStatusHandler(leavePermit).handle(leavePermit); 9 } 10 11 /** 12 * 根据假单获取StatusHandler 状态处理对象 13 * @param leavePermit 14 * @return 15 */ 16 public static StatusHandler getStatusHandler(LeavePermit leavePermit){ 17 return StatusHandlerRegistry.acquireStatusHandler(leavePermit.getLeavePermitType(),leavePermit.getStatus()); 18 } 19}

  所有的状态处理类都会保存在StatusHandlerRegistry对象中,该对象负责注册所有有关请假类型,状态和状态处理类的关系,每次都根据请假类型和状态去获取StatusHandler。

1public class StatusHandlerRegistry { 2 3 private static Map<String,StatusHandler> statusHandlerMap; 4 5 static { 6 statusHandlerMap=new ConcurrentHashMap<String, StatusHandler>(); 7 } 8 9 private StatusHandlerRegistry(){ 10 11 } 12 13 private static String getKey(LeavePermitType leavePermitType,Status status){ 14 return String.format("%s@-@%s",leavePermitType.getType(),status.name()); 15 } 16 17 /** 18 * 注册状态处理类 19 * @param leavePermitType 请假类型 20 * @param status 请假状态 21 * @param statusHandler 状态处理对象 22 */ 23 public static void registryStatusHandler(LeavePermitType leavePermitType,Status status,StatusHandler statusHandler){ 24 statusHandlerMap.put(getKey(leavePermitType,status),statusHandler); 25 } 26 27 /** 28 * 获取状态处理类 29 * @param leavePermitType 请假类型 30 * @param status 请假状态 31 * @return StatusHandler 32 */ 33 public static StatusHandler acquireStatusHandler(LeavePermitType leavePermitType,Status status){ 34 return statusHandlerMap.get(getKey(leavePermitType,status)); 35 } 36}

所以,在我们项目启动中,将请假类型,请假状态和状态处理对象StatusHandler注册到StatusHandlerRegistry中,当LeavePermitHandler 处理类接收到StatusHandlerEngine.post()的假单的时候,可以根据请假类型和状态获取相应的处理类StatusHandler,做相应状态逻辑的处理,逻辑处理结束,是否继续状态机取决于statusHandler的after方法是否调用goNextStatusHandler(leavePermit);在调用goNextStatusHandler(leavePermit)的时候,会去状态机获取下一个状态,StatusHandlerEngine.post(leavePermit)将继续去获取处理类statusHandler,这个时候,应为leavePermit的状态已经发生变化,所以获取到的statusHandler已经发生变化。
看一下运行结果:

1public static void main(String[] args) { 2 //注册年休假的状态和对应状态的处理类StatusHandler。 3 registryAnnualPermitStatusHandler(); 4 //注册病假的状态和对应状态的处理类StatusHandler。 5 registryMedicalPermitStatusHandler(); 6 7 LeavePermitHandler leavePermitHandler=new LeavePermitHandler(); 8 //状态机引擎接受事件处理类 9 StatusMachineEngine.addListener(leavePermitHandler); 10 //生成假单 11 LeavePermit leavePermit=new LeavePermit(); 12 leavePermit.setLeavePermitType(LeavePermitType.ANNUAL_LEAVE); 13 leavePermit.setStatus(Status.PERMIT_SUBMIT); 14 leavePermit.setUser("jettyrun"); 15 //假单交给引擎去执行 16 StatusMachineEngine.post(leavePermit); 17 System.out.println("----- 分割线 代表假条需要领导审批了,领导给个通过意见,然后状态机接着走-------"); 18 leavePermit.setEvent(Event.AGREE); 19 StatusMachineEngine.post(leavePermit); 20 System.out.println("----- 分割线 代表假条需要ceo审批了,ceo给个通过意见,然后状态机接着走-------"); 21 leavePermit.setEvent(Event.AGREE); 22 StatusMachineEngine.post(leavePermit); 23 System.out.println("--->>>>>>>>>end<<<<<<<<-------"); 24 25} 26 27 28 public static void registryAnnualPermitStatusHandler() { 29 30 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.PERMIT_SUBMIT, new AnnualPermitSubmitStatusHandler()); 31 32 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.LEADER_PERMIT_AGREE, new AnnualLeaderAgreeStatusHandler()); 33 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.LEADER_PERMIT_DISAGREE, new AnnualLeaderDisAgreeStatusHandler()); 34 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.LEADER_PERMIT_MODIFY, new AnnualLeaderPermitModifyStatusHandler()); 35 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.LEADER_PERMITING, new AnnualLeaderPermitingStatusHandler()); 36 37 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.CEO_PERMIT_AGREE, new AnnualCEOAgreeStatusHandler()); 38 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.CEO_PERMIT_DISAGREE, new AnnualCEODisAgreeStatusHandler()); 39 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.CEO_PERMIT_MODIFY, new AnnualCEOPermitModifyStatusHandler()); 40 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.CEO_PERMITING, new AnnualCEOPermitingStatusHandler()); 41 42 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.PERMIT_SUCCESS, new AnnualPermitSuccessStatusHandler()); 43 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.ANNUAL_LEAVE, Status.PERMIT_FAIL, new AnnualPermitFailStatusHandler()); 44 } 45 46 47 48 public static void registryMedicalPermitStatusHandler() { 49 50 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.PERMIT_SUBMIT, new MedicalPermitSubmitStatusHandler()); 51 52 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.LEADER_PERMIT_AGREE, new MedicalLeaderAgreeStatusHandler()); 53 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.LEADER_PERMIT_DISAGREE, new MedicalLeaderDisAgreeStatusHandler 54 ()); 55 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.LEADER_PERMIT_MODIFY, new MedicalLeaderPermitModifyStatusHandler()); 56 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.LEADER_PERMITING, new MedicalLeaderPermitingStatusHandler()); 57 58 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.HR_PERMIT_AGREE, new MedicalHrAgreeStatusHandler()); 59 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.HR_PERMIT_DISAGREE, new MedicalHrDisAgreeStatusHandler()); 60 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.HR_PERMIT_MODIFY, new MedicalHrPermitModifyStatusHandler()); 61 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.HR_PERMITING, new MedicalHrPermitingStatusHandler()); 62 63 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.PERMIT_SUCCESS, new MedicalPermitSuccessStatusHandler()); 64 StatusHandlerRegistry.registryStatusHandler(LeavePermitType.MEDICAL_LEAVE, Status.PERMIT_FAIL, new MedicalPermitFailStatusHandler()); 65 }

  执行结果:

1user:jettyrun--提交年休假假单--leavePermit status:permitSubmit 2user:jettyrun--领导审批年休假中--leavePermit status:leaderPermiting 3user:jettyrun--等待领导审批--leavePermit status:leaderPermiting 4----- 分割线 代表假条需要领导审批了,领导给个通过意见,然后状态机接着走------- 5user:jettyrun--领导审批年休假中--leavePermit status:leaderPermiting 6user:jettyrun--直线领导同意请年休假--leavePermit status:leaderAgree 7user:jettyrun--ceo审批年休假中--leavePermit status:ceoPermiting 8user:jettyrun--等待ceo审批--leavePermit status:ceoPermiting 9----- 分割线 代表假条需要领导审批了,ceo给个通过意见,然后状态机接着走------- 10user:jettyrun--ceo审批年休假中--leavePermit status:ceoPermiting 11user:jettyrun--ceo同意休年休假--leavePermit status:ceoAgree 12user:jettyrun--请年休假假成功--leavePermit status:permitSuccess 13--->>>>>>>>>end<<<<<<<<-------

可以看到,当需要领导,CEO审批假单的时候,状态机能够自动中断,领导,ceo同意了该请假请求leavePermit.setEvent(Event.AGREE);状态机就能够自动运行到最终状态permitSuccess。
这只是请年休假,再请一个病假

1LeavePermit leavePermit2=new LeavePermit(); 2 leavePermit2.setLeavePermitType(LeavePermitType.MEDICAL_LEAVE); 3 leavePermit2.setStatus(Status.PERMIT_SUBMIT); 4 leavePermit2.setUser("jettyrun2"); 5 StatusMachineEngine.post(leavePermit2); 6 7 System.out.println("----- 分割线 代表假条需要领导审批了,领导给个通过意见,然后状态机接着走-------"); 8 leavePermit2.setEvent(Event.AGREE); 9 StatusMachineEngine.post(leavePermit2); 10 11 12 System.out.println("----- 分割线 代表假条需要hr审批了,hr给个通过意见,然后状态机接着走-------"); 13 leavePermit2.setEvent(Event.AGREE); 14 StatusMachineEngine.post(leavePermit2); 15 System.out.println("--->>>>>>>>>end<<<<<<<<-------"); 16 17user:jettyrun2--病假提交--leavePermit status:permitSubmit-提交假单 18user:jettyrun2--领导审批病假中--leavePermit status:leaderPermiting-领导审批中 19user:jettyrun2--等待领导病假审批--leavePermit status:leaderPermiting-领导审批中 20----- 分割线 代表假条需要领导审批了,领导给个通过意见,然后状态机接着走------- 21user:jettyrun2--领导审批病假中--leavePermit status:leaderPermiting-领导审批中 22user:jettyrun2--领导同意休病假--leavePermit status:leaderAgree-领导同意 23user:jettyrun2--hr审批病假中--leavePermit status:hrPermiting-hr审批中 24user:jettyrun2--等待hr审批--leavePermit status:hrPermiting 25----- 分割线 代表假条需要hr审批了,hr给个通过意见,然后状态机接着走------- 26user:jettyrun2--hr审批病假中--leavePermit status:hrPermiting-hr审批中 27user:jettyrun2--hr同意休病假--leavePermit status:hrAgree-hr同意 28user:jettyrun2--成功病假审批--leavePermit status:permitSuccess-请假成功 29--->>>>>>>>>end<<<<<<<<-------

该状态机的设计思想有一部分借鉴公司的几个项目,一部分来源于当当elastic-job的源码解读心得。
源代码地址请点击我 github

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

EventBus - HelloWorld