20-10-10
banq
Java 15带来了密封类的预览功能。现在,我们基于接口的状态机不仅可以防止无效转换,而且可以像枚举一样枚举。
特点是:编译时和运行时两个阶段都能检查状态切换是否合法。
类型检查能自动帮助检查非法状态切换
使用Java编译时的类型检查,如果我们尝试直接从绿色过渡到红色,它将无法编译:
sealed interface TrafficLight extends State<TrafficLight> permits Green, SolidAmber, FlashingAmber, Red {} static final class Green implements TrafficLight, TransitionTo<SolidAmber> {} static final class SolidAmber implements TrafficLight, TransitionTo<Red> {} static final class Red implements TrafficLight, TransitionTo<FlashingAmber> {} static final class FlashingAmber implements TrafficLight, TransitionTo<Green> {} @Test public void traffic_light_typechecked_example() { Green signal = new Green();//绿色 // Comment out a transition and it will fail to compile.无法编译 signal = signal .transition(SolidAmber::new) .transition(Red::new) .transition(FlashingAmber::new) .transition(Green::new); } |
即使可能进行多个状态转换,我们仍然可以进行类型检查的转换:
static final class Pending implements OrderStatus, BiTransitionTo<CheckingOut, Cancelled> {} pending.transition(CheckingOut::new); // fine pending.transition(Cancelled::new); // fine pending.transition(Refunded::new); // Compile Error |
运行时检查非法状态切换
运行时也可以检查状态切换,如果无法切换,运行时则会抛出异常:
@Test public void runtime_transitions_possible() { TrafficLight light = new Green(); light = light .tryTransition(SolidAmber::new) .unchecked(); assertTrue(light instanceof SolidAmber); } @Test(expected = State.InvalidStateTransitionException.class) public void runtime_transitions_throw_exception_when_not_possible() { TrafficLight light = new Green(); light = light .tryTransition(Red::new) .unchecked(); } |
某个状态寻找
sealed interface OrderStatus extends State<OrderStatus> permits Pending, CheckingOut, Purchased, Shipped, Cancelled, Failed, Refunded {} @Test public void enumerable() { assertArrayEquals( array(Pending.class, CheckingOut.class, Purchased.class, Shipped.class, Cancelled.class, Failed.class, Refunded.class), State.values(OrderStatus.class) ); assertEquals(0, new Pending().ordinal()); assertEquals(3, new Shipped().ordinal()); assertEquals(Purchased.class, State.valueOf(OrderStatus.class, "Purchased")); assertEquals(Cancelled.class, State.valueOf(OrderStatus.class, "Cancelled")); |
提供values(), ordinal(), 和 valueOf()用于寻找状态:
static <T extends State<T>> List<Class> valuesList(Class<T> stateMachineType) { assertSealed(stateMachineType); return Stream.of(stateMachineType.permittedSubclasses()) .map(State::classFromDesc) .collect(toList()); } static <T extends State<T>> Class<T> valueOf(Class<T> stateMachineType, String name) { assertSealed(stateMachineType); return valuesList(stateMachineType) .stream() .filter(c -> Objects.equals(c.getSimpleName(), name)) .findFirst() .orElseThrow(IllegalArgumentException::new); } static <T extends State<T>, U extends T> int ordinal(Class<T> stateMachineType, Class<U> instanceType) { return valuesList(stateMachineType).indexOf(instanceType); } |
更多:on github
猜你喜欢