Sealed Java State Machines

muutama vuosi sitten kirjoitin siitä, miten toteuttaa valtion koneita, jotka sallivat vain voimassa siirtymät käännösaikaan Javassa.

tässä käytettiin rajapintoja enumien sijaan, jossa oli iso haittapuoli-et voinut taata, että tunnet kaikki mukana olevat valtiot. Joku voisi lisätä toisen valtion muualla codebase toteuttamalla käyttöliittymän.

Java 15 tuo tiivistettyjen luokkien esikatseluominaisuuden. Suljettujen luokkien avulla voimme ratkaista tämän varjopuolen. Nyt meidän käyttöliittymä perustuu valtion koneet voi vain estää virheellinen siirtymiä, mutta myös luetella kuten enums.

jos käytät JDK 15: tä esikatseluominaisuuksien ollessa käytössä, voit kokeilla koodia. Tältä näyttää rajapinnoilla varustetun valtiokoneiston määrittely.

sealed interface TrafficLight extensions State<TrafficLight> allows Green, SolidAmber, FlashingAmber, Red {}staattinen lopullinen luokka vihreä toteuttaa TrafficLight, transitio<SolidAmber> {}staattinen lopullinen luokka SolidAmber toteuttaa TrafficLight, transitio<Punainen> {}staattinen lopullinen luokka Punainen toteuttaa TrafficLight, transitio<FlashingAmber> {}staattinen lopullinen luokka viimeinen luokka Välähdyskammio toteuttaa Trafficlightin, siirtyminen<vihreä> {}

Uusi osa on “sinetöity ” ja”luvat”. Nyt tulee käännösvirhe määritellä Uusi toteutus TrafficLight

sekä nykyinen käyttäytyminen, jossa se on koota aika epäonnistuminen suorittaa siirtymän, että liikennevalot eivät salli.

n.b. Voit myös ohittaa käännöksen ajan Tarkistetun version ja käyttää silti tyyppimäärittelyjä siirtymien tarkistamiseen.

moninaiset siirtymät ovat mahdollisia myös tilasta

staattinen lopullinen luokka vireillä olevat Työtilaukset, Bittiransitio<CheckingOut, Cancelled> {}

kiitos suljettu luokat voimme myös nyt tehdä enum tyyli luettelointi ja lookups meidän käyttöliittymä perustuu valtion koneita.

sealed interface OrderStatus extends State<OrderStatus> luvat vireillä, CheckingOut, buyed, Shipped, Cancelled, Failed, Refuged {} @Test public void enumerable() { assertArrayEquals( array(Pending.Luokka, lähtöselvitys.Luokka, ostettu.Luokka, lähetetty.tunti peruttu.Luokka epäonnistui.Luokka, hyvitetään.Luokka), osavaltio.arvot (OrderStatus.Luokka)); assertEquals(0, uusi vireillä ().ordinaali ()); assertEquals(3, new Shipped ().ordinaali ()); assertEquals(ostettu.Luokka, osavaltio.arvo (OrderStatus.Luokka, "ostettu"); assertEquals(peruutettu.Luokka, osavaltio.arvo (OrderStatus.Luokka, "peruttu"));}

nämä ovat mahdollisia, koska JEP 360 tarjoaa reflection API, jolla voidaan luetella sallitut alaluokat rajapinnan. (side note the JEP says getpermittedsublasss() but the implementation seems to use permittedsublasss() )
we can add use this to add the above convenience methods to our State interface to allow the values(), ordinal(), and value of() lookups.

static <T extends State<T>> List<Class> valuesList(Class<T> stateMachineType) { assertSealed(stateMachineType); return Stream.of (stateMachineType.sallitut alaluokat ()).Kartta (tila:: classFromDesc).keräily (tolisti ());} 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 lisätietoja siitä, miten siirtymätarkastus toimii ja lisää esimerkkejä siitä, missä tämä voisi olla hyödyllistä alkuperäisessä postitse. Koodi on GitHubissa.

Vastaa

Sähköpostiosoitettasi ei julkaista.