Sigilate Java Stat mașini

câțiva ani în urmă am postat despre cum să pună în aplicare mașini de stat care permit doar tranziții valide la momentul compilării în Java.

aceasta a folosit interfețe în loc de enums, care au avut un mare dezavantaj—nu ați putea garanta că cunoașteți toate statele implicate. Cineva ar putea adăuga un alt stat în altă parte în codebase prin implementarea interfeței.

Java 15 aduce o caracteristică de previzualizare a claselor sigilate. Clasele sigilate ne permit să rezolvăm acest dezavantaj. Acum, mașinile noastre de stat bazate pe interfață nu numai că pot preveni tranzițiile nevalide, dar pot fi și enumerabile ca enums.

dacă utilizați jdk 15 cu funcții de previzualizare activate, puteți încerca codul. Acesta este modul în care se pare pentru a defini o mașină de stat cu interfețe.

trafficlight interfață sigilată extinde starea<TrafficLight> permite Verde, SolidAmber, FlashingAmber, roșu {}static clasa finală verde implementează TrafficLight, TransitionTo<SolidAmber> {}static clasa finală SolidAmber implementează TrafficLight, TransitionTo<Red> {}static clasa finală roșu implementează TrafficLight, TransitionTo<FlashingAmber> {}static clasa finală roșu implementează TrafficLight, TransitionTo<FlashingAmber > clasa finală Flashingamber implementează trafficlight, Transitionto < verde> {}

noua parte este “sigilată”și ” permise”. Acum devine un eșec de compilare pentru a defini o nouă implementare a TrafficLight

, precum și comportamentul existent în cazul în care este un eșec de compilare timp pentru a efectua o tranziție care semafoare nu permit.

n.b. de asemenea, puteți sări peste versiunea bifată a timpului de compilare și puteți utiliza în continuare definițiile de tip pentru a verifica tranzițiile în timpul rulării.

tranzițiile Multiple sunt posibile și dintr-o stare

clasa finală statică în așteptare implementează OrderStatus, BiTransitionTo< CheckingOut, anulat> {}

datorită claselor sigilate, putem face acum enumerarea stilului enum și căutările pe mașinile noastre de stare bazate pe interfață.

interfață sigilată OrderStatus extinde starea<OrderStatus > permise în așteptare, CheckingOut, achiziționate, expediate, anulate, eșuate, rambursate {} @test public void enumerable() { assertArrayEquals( array(în așteptare.clasă, Check-out.clasă, cumpărată.clasă, expediat.clasă, anulată.clasă, A eșuat.clasă, rambursată.clasa), Stat.valori (OrderStatus.clasa)); assertEquals (0, nou în așteptare ().ordinal ()); assertEquals(3, Nou expediate ().ordinal ()); asertequal(achiziționat.clasă, Stat.valueOf (OrderStatus.clasa, "cumpărat")); asertegaluri(anulate.clasă, Stat.valueOf (OrderStatus.clasa, "anulat"));}

acestea sunt posibile deoarece JEP 360 oferă un API de reflecție cu care se pot enumera subclasele permise ale unei interfețe. (notă laterală JEP spune getPermittedSubclasses () dar implementarea pare să utilizeze permittedSubclasses ())
putem adăuga utilizați acest lucru pentru a adăuga metodele de conveniență de mai sus la interfața noastră de Stat pentru a permite căutările values (), ordinal() și valueOf ().

static <t extinde starea <T>>lista< clasa>valuesList(clasa< T> stateMachineType) { assertSealed(stateMachineType); return Stream.de (stateMachineType.permise subclase ()).hartă (Stat:: classFromDesc) .colecta(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);}

există mai multe detalii despre modul în care funcționează verificarea tranziției și mai multe exemple despre locul în care acest lucru ar putea fi util în postarea originală. Codul este pe github.

Lasă un răspuns

Adresa ta de email nu va fi publicată.