Sealed Java State Machines

néhány évvel ezelőtt írtam arról, hogyan lehet olyan állapotgépeket megvalósítani, amelyek csak fordítási időben engedélyezik az érvényes átmeneteket Java-ban.

ez interfészeket használt az enums helyett, amelynek nagy hátránya volt—nem tudta garantálni, hogy ismeri az összes érintett állapotot. Valaki felvehet egy másik állapotot a kódbázisba a felület megvalósításával.

a Java 15 a lezárt osztályok előnézeti funkcióját hozza létre. A lezárt osztályok lehetővé teszik számunkra, hogy megoldjuk ezt a hátrányt. Most a felület alapú állami gépek nem csak megakadályozza érvénytelen átmenetek, hanem lehet számlálható, mint enums.

ha a JDK 15-öt használja az előnézeti funkciók engedélyezésével, kipróbálhatja a kódot. Így néz ki egy interfészekkel rendelkező állapotgép meghatározása.

zárt interfész TrafficLight kiterjeszti állapot<TrafficLight> zöld, SolidAmber, FlashingAmber, piros {}statikus végső osztály Zöld megvalósítja TrafficLight, TransitionTo<SolidAmber> {}statikus végső osztály SolidAmber végrehajtja TrafficLight, TransitionTo<Red> {}statikus végső osztály Red végrehajtja TrafficLight, TransitionTo<FlashingAmber> {}statikus végső osztály végső osztály Flashingamber végrehajtja TrafficLight, Transitionto<zöld> {}

az új rész “lezárt” és “engedélyek”. Most ez lesz a fordítási hiba, hogy meghatározza egy új végrehajtását TrafficLight

, valamint a meglévő viselkedés, ahol ez egy fordítási idő elmulasztása az átmenet, hogy a közlekedési lámpák nem teszik lehetővé.

n.b. kihagyhatja a fordítási időben ellenőrzött verziót is, és továbbra is használhatja a típusdefiníciókat az átmenetek futásidejű ellenőrzéséhez.

több átmenet is lehetséges egy állapotból

statikus végső osztály függőben lévő végrehajtók OrderStatus, BiTransitionTo<CheckingOut, törölve> {}

a zárt osztályoknak köszönhetően most már enum stílusú felsorolást és kereséseket is végezhetünk interfész alapú állapotgépeinken.

lezárt interfész OrderStatus kiterjeszti állapot< OrderStatus> engedélyek függőben, CheckingOut, vásárolt, szállított, törölt, sikertelen, visszatérített {} @Test public void enumerable() { assertArrayEquals( tömb(függőben.osztály, kijelentkezés.osztály, vásárolt.osztály, szállítva.óra, lemondva.osztály, nem sikerült.osztály, Visszatérítve.osztály), állapot.értékek (OrderStatus.osztály)); assertEquals (0, új függőben ().ordinal ()); assertEquals(3, új szállított ().ordinal ()); assertEquals(vásárolt.osztály, állam.valueOf (OrderStatus.osztály," vásárolt")); assertEquals(törölve.osztály, állam.valueOf (OrderStatus.osztály, "törölve"));}

ezek azért lehetségesek, mert a JEP 360 egy reflection API-t biztosít, amellyel felsorolhatjuk az interfész megengedett alosztályait. (megjegyzés: a JEP azt mondja, hogy getPermittedSubclasses (), de a megvalósítás úgy tűnik, hogy a permittedSubclasses ())
hozzáadhatjuk ezt a fenti kényelmi módszerek hozzáadásához az Állapotinterfészünkhöz, hogy engedélyezzük az (), ordinal() és valueOf () kereséseket.

statikus <T kiterjeszti az állapotot<T>>List< Class>valuesList(Class< T> stateMachineType) { assertSealed(stateMachineType); visszatérési adatfolyam.nak, - nek(stateMachineType.permittedSubclasses ()).térkép (állapot:: classFromDesc) .gyűjtés (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);}

további részletek találhatók az átmenet ellenőrzésének működéséről, valamint további példák arra, hogy ez hol lehet hasznos az eredeti bejegyzésben. A kód a GitHubon található.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.