Sealed Java State Machines

před několika lety jsem zveřejnil informace o tom, jak implementovat státní stroje, které povolují platné přechody pouze v době kompilace v Javě.

toto používalo rozhraní místo enumů, což mělo velkou nevýhodu—nemohli jste zaručit, že znáte všechny zúčastněné státy. Někdo by mohl přidat další stav jinde ve vaší kódové základně implementací rozhraní.

Java 15 přináší funkci náhledu zapečetěných tříd. Uzavřené třídy nám umožňují vyřešit tuto nevýhodu. Nyní naše rozhraní založené stavové stroje mohou nejen zabránit neplatné přechody, ale také být vyjmenovat jako enums.

pokud používáte jdk 15 s aktivovanými funkcemi náhledu, můžete kód vyzkoušet. Takto to vypadá definovat stavový stroj s rozhraními.

sealed interface TrafficLight rozšiřuje stav<TrafficLight> povoluje zelenou, SolidAmber, FlashingAmber, červenou {}static final class Green implementuje TrafficLight, TransitionTo<SolidAmber> {}static final class SolidAmber implementuje TrafficLight, TransitionTo<Red> {}static final class Red implementuje TrafficLight, TransitionTo<FlashingAmber> {}static Final class FlashingAmber implementuje TrafficLight, TransitionTo<FlashingAmber > {} přechod na < Zelená> {}

nová část je “zapečetěna” a “povolení”. Nyní se stává selhání kompilace definovat novou implementaci TrafficLight

, stejně jako stávající chování, kde je to Kompilace čas selhání provést přechod, který semafory neumožňují.

n. b.můžete také přeskočit čas kompilace kontrolovanou verzi a stále používat definice typu pro kontrolu přechodů za běhu.

více přechodů je možné i ze stavu

statická konečná třída čekající na implementaci OrderStatus, BiTransitionTo<kontrola, zrušeno> {}

díky zapečetěným třídám můžeme nyní také provádět výčet stylů enum a vyhledávání na našich stavových strojích založených na rozhraní.

sealed interface OrderStatus rozšiřuje stav< OrderStatus> povolení čekající, CheckingOut, zakoupené, dodané, zrušené, neúspěšné, vrácené {} @Test public void enumerable() { assertArrayEquals( array(čekající.třída, kontrola.třída, zakoupeno.třída, odesláno.hodina zrušena.třída, selhala.třída, vráceno.třída), stát.hodnoty (OrderStatus.třída)); assertEquals (0, nové čekající ().ordinal ()); assertEquals (3, nové odesláno ().ordinal ()); assertEquals(zakoupeno.třída, stát.valueOf (OrderStatus.třída, "zakoupeno")); assertEquals (zrušeno.třída, stát.valueOf (OrderStatus.třída, "zrušeno"));}

to je možné, protože JEP 360 poskytuje reflexní API, pomocí kterého lze vyjmenovat povolené podtřídy rozhraní. (boční poznámka JEP říká getPermittedSubclasses (), ale zdá se, že implementace používá permittedSubclasses ())
můžeme přidat použít k přidání výše uvedených metod pohodlí do našeho státního rozhraní, abychom umožnili vyhledávání hodnot (), ordinal () a valueOf ().

static <t extends State<T>> List<Class> valuesList(Class<T> stateMachineType) { assertSealed (stateMachineType); return Stream.z (stateMachineType.povolené třídy ()).mapa (stát:: classFromDesc).sbírat (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);}

v původním příspěvku je více podrobností o tom, jak kontrola přechodu funguje, a další příklady toho, kde by to mohlo být užitečné. Kód je na Githubu.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.