A minták helyes használatához Állapotés Stratégia A Java-alkalmazások lényegében fontos, hogy a Java programozók világosan megértsék a kettő közötti különbséget. Bár mind az állapot, mind a stratégia sablonok hasonló felépítésűek, és mindkettő a nyitott/zárt elven alapul, ami a SOLID elvekben az „O”-t jelenti, teljesen eltérőek szándékait. minta Stratégia Java nyelven kapszulázáshoz használják kapcsolódó algoritmuskészletek, amelyek végrehajtási rugalmasságot biztosítanak az ügyfél számára. Az ügyfél bármely algoritmust választhat futási időben anélkül, hogy megváltoztatná a Strategy objektumot használó osztály kontextusát. Néhány népszerű minta példa Stratégia olyan kódot ír, amely olyan algoritmusokat használ, mint a titkosítás, a tömörítés vagy a rendezés. Másrészt az állapotminta lehetővé teszi, hogy egy objektum különböző állapotokban eltérően viselkedjen. Mert a való világban egy objektumnak gyakran vannak állapotai és másként viselkedik benne különböző államok pl egy automata csak akkor ad el árut, ha hasCoin állapotban van, addig nem árul, amíg nem teszel bele egy érmét. Most már jól látható a különbség a Stratégia és az Állami minták között, más a szándék. Az állapotminta segít az objektumnak az állapot kezelésében, míg a Stratégia minta lehetővé teszi az ügyfél számára, hogy más viselkedést válasszon. Egy másik különbség, amelyet nem olyan könnyű észrevenni, az, hogy ki irányítja a viselkedésbeli változást. A Stratégia minta esetében a kliens az, aki különböző stratégiákat ad a kontextushoz, az állapotmintában az átmenetet maga a kontextus vagy az objektum állapota irányítja. Ezen túlmenően, ha saját kezűleg kezeli a State objektum állapotváltozásait, akkor a kontextusra való hivatkozásnak kell lennie, például egy automatában lehetővé kell tenni a setState() metódus meghívását a kontextus aktuális állapotának megváltoztatásához. Másrészt a Stratégia objektum soha nem tartalmaz hivatkozást a kontextusra, az ügyfél maga adja át a választott Stratégiát a kontextusnak. Az állapot- és stratégiaminták közötti különbség az egyik népszerű interjúkérdés a Java-mintákkal kapcsolatban, ebben a Java-mintákkal foglalkozó cikkben ezt fogjuk közelebbről megvizsgálni. Megvizsgálunk néhány hasonlóságot és különbséget a Java stratégiai és állapotmintái között, hogy segítsünk jobban megérteni ezeket a mintákat.

Hasonlóságok az állapot- és stratégiai minták között

Ha megnézi az állapot- és stratégiai minták UML-diagramját, észre fogja venni, hogy mindkettő hasonlít egymásra. Az objektumot, amely állapotot használ a viselkedésének megváltoztatására, kontextus objektumnak nevezzük, hasonlóképpen azt az objektumot, amely stratégiát használ a viselkedésének megváltoztatására, kontextus objektumnak nevezik. Ne feledje, hogy az ügyfél interakcióba lép a Context objektummal. Az állapotminta esetén a kontextus a hívási metódusokat delegálja az aktuális objektumként tartott állapot objektumra, míg a Strategy minta esetében a kontextus a Strategy objektumot használja paraméterként, vagy a létrehozás során megadja. az objektumkörnyezetről. UML állapotminta diagram Java nyelven
Ez az állapotminta UML-diagramja az objektum-orientált árusítóautomaták Java nyelven történő létrehozásának klasszikus problémáját mutatja be. Látható, hogy az automata állapota egy interfész segítségével van ábrázolva, amely ezután rendelkezik egy megvalósítással, amely egy adott állapotot reprezentál. Minden állapot hivatkozik az objektum kontextusára is, hogy a kontextusban meghívott műveletek eredményeképpen áttérhessen egy másik állapotba.
Ez a stratégiai minta UML diagramja különféle funkcionális megvalósításokat tartalmaz. Mivel sok rendezési algoritmus létezik, ez a tervezési minta lehetővé teszi az ügyfél számára, hogy algoritmust válasszon az objektumok rendezésekor. Valójában Java Collection keretrendszer ezt a mintát használja ki a Collections.sort() metódus megvalósításával, amely a Java objektumok rendezésére szolgál. Az egyetlen különbség az, hogy ahelyett, hogy lehetővé tenné az ügyfél számára a rendezési algoritmus kiválasztását, lehetővé teszi az ügyfél számára, hogy összehasonlítási stratégiát adjon meg a Java Comparator vagy Comparable felületének egy példányának átadásával. Nézzünk meg néhány hasonlóságot a Java két fő tervezési mintája között:
  1. Mindkét minta, az állapot és a stratégia, megkönnyíti az új állapotok és stratégiák hozzáadását anélkül, hogy befolyásolná az őket használó objektum környezetét.

  2. Mindkettő nyitva/zárva tartja a kódot, ami azt jelenti, hogy a kialakítás nyitott lesz a bővítményekre, de zárva van a módosításokra. Az Állapot és a Stratégia minták esetében az objektum kontextusa zárva van a módosítások, új állapotok vagy új irányelvek bevezetése előtt, vagy nincs szükség más állapot kontextusának módosítására, vagy minimális változtatásokra.

  3. Ahogy az objektumkontextus egy objektum inicializálási állapotával kezdődik az állapotmintában, az objektumkontextusnak is van alapértelmezett stratégiája a Java stratégiai mintája esetén.

  4. Az Állapot minta különböző viselkedéseket reprezentál különböző objektumállapotok formájában, míg a Stratégia minta különböző viselkedéseket különböző objektum stratégiák formájában.

  5. Mindkét minta, a stratégia és az állapot, alosztályoktól függ a viselkedés megvalósításához. Minden egyes konkrét stratégia kiterjeszti az absztrakt stratégiát, minden állapot egy interfész vagy absztrakt osztály alosztálya, amelyet az állapot ábrázolására használnak.

A Java stratégiai és állapotmintái közötti különbségek

Tehát most már tudjuk, hogy az Állam és a Stratégia minták felépítésében hasonlóak, de szándékaik eltérőek. Nézzünk meg néhány fő különbséget ezek között a tervezési minták között.
  1. A stratégia minta összefüggő algoritmusok halmazát foglalja magában, és lehetővé teszi az ügyfél számára, hogy felcserélhető viselkedéseket alkalmazzon a kompozíció és a futásidejű delegálás ellenére, másrészt az állapotminta segít egy osztálynak, hogy különböző viselkedéseket mutasson különböző állapotokban.

  2. A következő különbség az állapot és a stratégia minták között az, hogy az állapot egy objektum állapotát, míg a stratégia minta egy algoritmust vagy stratégiát foglal magában. Mivel az állapot egy objektumhoz van társítva, nem használható fel újra, de a stratégiát vagy algoritmust a kontextustól elválasztva újra felhasználhatjuk.

  3. Az állapotmintában a magánállapot tartalmazhat hivatkozást az állapotátmenetek végrehajtásának kontextusára, de a stratégia nem tartalmaz hivatkozást arra a kontextusra, ahol használják.

  4. A stratégia megvalósítása paraméterként átadható annak az objektumnak, amely használni fogja, például a Collection.sort() vesz egy Comparator-t, amely a stratégia. Másrészt az állapot magának az objektumkörnyezetnek a része, és idővel az objektumkontextus egyik állapotból a másikba vált át.

  5. Bár a Stratégia és az Állam is a nyitott/zárt elvet követi, a Stratégia is az Egységes Felelősség Elvét követi, mivel minden stratégia egyedi algoritmust tartalmaz, a különböző stratégiák függetlenek egymástól. Egy stratégia megváltoztatásához nincs szükség egy másik stratégia megváltoztatására.

  6. Egy másik elméleti különbség a Stratégia és az Állapot minták között, hogy az alkotó határozza meg az objektum „Hogyan” részét, például „Hogyan” a rendezési objektum rendezi az adatokat, másrészt az állapotminta határozza meg a „mit” és „mikor” az objektum részei, például, mit tud tenni egy objektum, ha egy bizonyos állapotban van.

  7. Az állapotmintában jól meghatározott az állapotátmenet sorrendje, a Stratégia mintánál nincs ilyen követelmény. Az Ügyfél szabadon választhatja meg a Stratégia tetszőleges megvalósítását.

  8. A stratégia mintázatának néhány gyakori példája az algoritmusok beágyazása, mint például a rendezési, titkosítási vagy tömörítési algoritmusok. Ha látja, hogy a kódot használnia kell különböző fajták kapcsolódó algoritmusok esetén érdemes megfontolni a Stratégia minta használatát. Másrészt az állapotminta használatának lehetőségének felismerése meglehetősen egyszerű, ha az állapot- és állapotátmeneteket sok egymásba ágyazott feltételes utasítás nélkül kell kezelni.

  9. Az utolsó, de az egyik legfontosabb különbség az Állapot és a Stratégia minták között, hogy a Stratégia megváltoztatását az Ügyfél, míg az Állapot megváltoztatását maga az objektum kontextusa vagy állapota is megteheti.

Minden arról szól különbség a Java állapot- és stratégiamintái között. Mint mondtam, mindkettő hasonlónak tűnik az osztályaikban és az UML-diagramjaikban, mindkettő nyitott/zárt elvet biztosít, és beágyazott viselkedést biztosít. Használja a Stratégiai mintát egy olyan algoritmus vagy stratégia beágyazására, amely futási időben egy kontextushoz kerül, esetleg paraméterként vagy összetett objektumként, és használja az állapotmintát a Java állapotátmenetek vezérlésére. Eredeti "mintaÁllapot".ru forrás

Állapot - az objektumok viselkedési mintája, amely attól függően eltérő funkcionalitást határoz meg belső állapot tárgy. webhely oldal eredeti forrása

Feltételek, Feladat, Időpont egyeztetés

Lehetővé teszi egy objektum számára, hogy a belső állapota alapján változtassa viselkedését. Mivel a viselkedés teljesen tetszőlegesen, korlátozások nélkül változhat, kívülről úgy tűnik, hogy az objektum osztálya megváltozott.

Motiváció

Vegye figyelembe az osztályt TCPConnection, amely bemutatja internetkapcsolat. Ennek az osztálynak az objektuma számos állapot egyikében lehet: Alapított(telepítve) hallgat(hallgat), zárva(zárva). Amikor az objektum TCPConnection kéréseket fogad más objektumoktól, majd az aktuális állapottól függően eltérően válaszol. Például egy kérésre adott válasz nyisd ki(nyitott) attól függ, hogy a kapcsolat állapotban van-e zárva vagy Alapított. Az állapotminta leírja, hogy egy objektum hogyan TCPConnection különböző állapotokban eltérően viselkedhet. source.ru

Ennek a mintának a fő gondolata egy absztrakt osztály bevezetése TCPState különböző kapcsolódási állapotok ábrázolására. Ez az osztály deklarál egy interfészt, amely közös minden olyan osztályban, amely különféle működő sources.ru-t ír le

Államok. Ezekben az alosztályokban TCPStateállapotspecifikus viselkedés valósul meg. Például az órákon A TCPE létrehozvaés TCPCzárvaállapotspecifikus viselkedés valósult meg Alapítottés zárva illetőleg. webhely oldal eredeti forrása

oldal eredeti forrásoldala

Osztály TCPConnectionállapotobjektumot tárol (egy alosztály példányát TCPState), amely a kapcsolat aktuális állapotát képviseli, és az összes állapotspecifikus kérést erre az objektumra delegálja. TCPConnection saját alosztálypéldányát használja TCPState elég egyszerű: az egységes felület metódusainak meghívása TCPState, csak attól függően, hogy melyik Ebben a pillanatban egy adott alosztály kerül tárolásra TCPState-a - más az eredmény, pl. a valóságban olyan műveleteket hajtanak végre, amelyek erre a kapcsolati állapotra jellemzőek. Original.ru forrás

És minden alkalommal, amikor a kapcsolat állapota megváltozikTCPConnection megváltoztatja állapotobjektumát. Például ha egy létrejött kapcsolat bezárul, TCPConnection lecseréli egy osztály példányát A TCPE létrehozva példa TCPCzárva. oldal eredeti forrásoldala

Az alkalmazás jelei, a minta használata Állapot (State)

Használja az állapotmintát a következő esetekben: forrás original.ru
  1. Amikor egy objektum viselkedése az állapotától függ, és futási időben meg kell változnia. .ru
  2. Ha többágú műveletek vannak az opcode-ban feltételes állítások, amelyben az ágválasztás az államtól függ. Jellemzően ebben az esetben az állapotot felsorolt ​​konstansok képviselik. Gyakran ugyanaz a feltételes utasításstruktúra több utasításban is megismétlődik.Az állapotminta azt sugallja, hogy minden ágat külön osztályba kell helyezni. Ez lehetővé teszi, hogy egy objektum állapotát független objektumként kezeljük, amely másoktól függetlenül változhat. forrás original.ru

Megoldás

oldal forrásoldal eredeti

original.ru

Az állami minta résztvevői

forrás original.ru
  1. Kontextus(TCPConnection) - kontextus.
    Egyetlen felületet határoz meg az ügyfelek számára.
    Egy alosztály példányát tárolja ConcreteState, amely meghatározza az aktuális állapotot. original.ru
  2. Állapot(TCPState) - állapot.
    Interfészt határoz meg a Kontextus egy adott állapotához kapcsolódó viselkedés beágyazásához. forrás original.ru
  3. Alosztályok ConcreteState(TCPEstablished, TCPListen, TCPClosed) - adott állapot.
    Mindegyik alosztály valamilyen kontextusállapothoz kapcsolódó viselkedést valósít meg. Kontextus. webhely oldal eredeti forrása

Az állapotminta használatának sémája

Osztály Kontextus kéréseket delegál az aktuális objektumhoz ConcreteState. webhely oldal eredeti forrása

A kontextus átadhatja magát argumentumként egy objektumnak Állapot Az, amelyik feldolgozza a kérést. Ez lehetővé teszi az állapot objektum ( ConcreteState) szükség esetén elérje a kontextust. oldal eredeti forrásoldala

Kontextus az ügyfelek fő felülete. Az ügyfelek állapotobjektumokkal konfigurálhatják a környezetet Állapot(pontosabban ConcreteState). A kontextus konfigurálása után az ügyfeleknek többé nem kell közvetlenül kommunikálniuk az állapotobjektumokkal (csak a közös felületen keresztül Állapot). oldal forrásoldal eredeti

Ugyanakkor akár Kontextus, vagy maguk az alosztályok ConcreteState el tudja dönteni, hogy milyen feltételek mellett és milyen sorrendben történik az állapotváltozás. .ru forrás

Az államminta végrehajtásával kapcsolatos kérdések

Az államminta megvalósításával kapcsolatos kérdések: Original.ru forrás
  1. Mi határozza meg az állapotok közötti átmeneteket.
    Az állapotminta semmit sem mond arról, hogy melyik résztvevő határozza meg az állapotok közötti átmenet feltételeit (kritériumait). Ha a kritériumok rögzítettek, akkor közvetlenül az osztályban implementálhatók Kontextus. Általában azonban rugalmasabb és a helyes megközelítés az, hogy az osztály alosztályait maguknak engedjük Állapot határozza meg a következő állapotot és átmeneti pillanatot. Erre az osztályban Kontextus hozzá kell adnia egy felületet, amely lehetővé teszi az objektumokból Állapotállítsa be az állapotát.
    Ez a decentralizált átmeneti logika könnyebben módosítható és bővíthető – csak új alosztályokat kell meghatározni Állapot. A decentralizáció hátránya, hogy minden alosztály Állapot„tudnia” kell legalább még egy másik állapot alosztályát (amelyre ténylegesen át tudja kapcsolni az aktuális állapotot), ami implementációs függőséget vezet be az alosztályok között. source.ru

    oldal forrásoldal eredeti
  2. Táblázat alternatíva.
    Van egy másik módja az állapotvezérelt kód felépítésének. Ez a véges állapotú gép elve. Táblázatot használ a bemenet állapotátmenetekhez való leképezéséhez. Segítségével meghatározható, hogy bizonyos bemeneti adatok érkezésekor melyik állapotba szeretnénk kerülni. Lényegében ezzel a feltételes kódot táblakereséssel helyettesítjük.
    Az automata fő előnye a rendszeresség: az átmenet kritériumainak megváltoztatásához elég csak az adatokat módosítani, a kódot nem. De vannak hátrányai is:
    - a táblázatkeresések gyakran kevésbé hatékonyak, mint a függvényhívások,
    - az átmeneti logika egységes táblázatos formátumban történő bemutatása kevésbé egyértelművé teszi a kritériumokat, és ezért nehezebben érthetővé teszi,
    - általában nehéz az állapotátmeneteket kísérő akciók hozzáadása. A táblázatos módszer figyelembe veszi az állapotokat és a köztük lévő átmeneteket, de ki kell bővíteni, hogy minden állapotváltozással tetszőleges számításokat lehessen végezni.
    A tábla alapú állapotgépek és az állapotminta közötti fő különbség a következőképpen foglalható össze: Az állapotminta állapotspecifikus viselkedést modellez, míg táblázatos módszer az állapotok közötti átmenetek meghatározását hangsúlyozza. Original.ru forrás

    source.ru eredeti
  3. Állami objektumok létrehozása és megsemmisítése.
    A fejlesztési folyamat során általában a következők közül kell választania:
    - állapotobjektumok létrehozása, amikor szükség van rájuk, és használat után azonnali megsemmisítése,
    - előre és örökre létrehozva őket.

    Az első lehetőség akkor előnyös, ha nem tudni előre, hogy a rendszer mely állapotokba kerül, és a kontextus viszonylag ritkán változtatja meg az állapotot. Ennek során nem hozunk létre olyan objektumokat, amelyeket soha nem fogunk használni, ami elengedhetetlen, ha sok információt tárolunk az állapotobjektumokban. Ha az állapotváltozások gyakran előfordulnak, és nem akarjuk megsemmisíteni az őket reprezentáló objektumokat (mert hamarosan újra szükség lehet rájuk), akkor a második megközelítést érdemes alkalmazni. Az időt csak egyszer, a legelején fordítjuk a tárgyak létrehozására, a pusztításra pedig egyáltalán nem. Igaz, ez a megközelítés kényelmetlen lehet, mivel a kontextusnak minden olyan állapotra utalást kell tárolnia, amelybe a rendszer elméletileg beleeshet. source.ru eredeti

    oldal forrásoldal eredeti
  4. Dinamikus változás használata.
    Igény szerint változtathatja a viselkedést az objektum osztályának futás közbeni megváltoztatásával, de ez a legtöbb objektumorientált nyelven nem támogatott. Ez alól kivételt képeznek a Perl, a JavaScript és más szkript-alapú nyelvek, amelyek ilyen mechanizmust biztosítanak, és ezért közvetlenül fenntartják a mintaállapotot. Ez lehetővé teszi az objektumok számára, hogy az osztálykódjuk megváltoztatásával változtassák viselkedésüket. source.ru eredeti

    eredeti forrás.ru

eredmények

Használat eredményei minta állapota: Original.ru forrás
  1. Állapotspecifikus viselkedést lokalizál.
    És állapotoknak megfelelő részekre osztja. Az állapotminta az adott állapothoz kapcsolódó összes viselkedést belehelyezi külön tárgy. Mivel az állapotfüggő kód teljes egészében az osztály egyik alosztályába tartozik Állapot, akkor egyszerűen új alosztályok generálásával új állapotokat és átmeneteket adhat hozzá.
    Ehelyett adattagokat használhatunk a belső állapotok, majd az objektum műveleteinek meghatározására Kontextus ellenőrizze ezeket az adatokat. De ebben az esetben a hasonló feltételes vagy elágazó utasítások szétszórva lennének az osztálykódban. Kontextus. Ugyanakkor egy új állapot hozzáadásához több művelet megváltoztatása szükséges, ami megnehezítené a karbantartást. Az állapotminta megoldja ezt a problémát, de egy másikat is létrehoz, mivel a különböző állapotok viselkedése több alosztály között oszlik meg. Állapot. Ez növeli az osztályok számát. Természetesen egy osztály kompaktabb, de ha sok állapot van, akkor egy ilyen eloszlás hatékonyabb, mert különben nehézkes feltételes utasításokkal kellene számolni.
    Nem kívánatos a nehézkes feltételes kijelentések jelenléte, valamint a hosszú eljárások jelenléte. Túl monolitikusak, ezért a kódmódosítás és -bővítés problémát jelent. Az állapotminta jobb módot kínál az állapotfüggő kód strukturálására. Az állapotátmeneteket leíró logika többé nincs monolitikus utasításokba csomagolva ha vagy kapcsoló, de alosztályok között elosztva Állapot. Minden egyes átmenetet és cselekvést egy osztályba foglalva az állapot teljes értékű objektummá válik. Ez javítja a kód szerkezetét és tisztázza a célját. forrás original.ru
  2. Explicitté teszi az állapotok közötti átmeneteket.
    Ha egy objektum az aktuális állapotát kizárólag belső adatok alapján határozza meg, akkor az állapotátmeneteknek nincs kifejezett reprezentációja; csak egyes változókhoz való hozzárendelésként jelennek meg. A különböző állapotokhoz külön objektumok megadása egyértelműbbé teszi az átmeneteket. Ezen kívül tárgyak Állapot megvédheti a kontextust Kontextus a belső változók nem illesztéséből, hiszen az átmenetek a kontextus szempontjából atomi cselekvések. Az átmenet megvalósításához csak egy változó értékét kell megváltoztatnia (objektumváltozó Állapot osztályban Kontextus), nem csak néhány. Original.ru forrás
  3. Az állapotobjektumok megoszthatók.
    Ha az állapotobjektumban Állapot nincsenek példányváltozók, azaz az általa képviselt állapotot kizárólag maga a típus kódolja, akkor különböző kontextusok osztozhatnak ugyanazon az objektumon Állapot. Ha az állapotokat így választjuk el, akkor ezek lényegében légysúlyok (lásd a légysúly mintát), amelyeknek nincs belső állapotuk, csak viselkedésük van. oldal forrás eredeti webhely

Példa

Tekintsük a példa megvalósítását a " " szakaszból, azaz. egyszerű TCP kapcsolati architektúra felépítése. Ez a TCP protokoll egyszerűsített változata, természetesen nem reprezentálja a teljes protokollt és még csak nem is a TCP kapcsolatok összes állapotát. webhely eredeti webhely forrása

Először is határozzuk meg az osztályt TCPConnection, amely interfészt biztosít az adatátvitelhez és kezeli az állapotváltoztatási kéréseket: TCPConnection . source.ru eredeti

Egy tagváltozóban állapot osztály TCPConnection az osztály egy példánya tárolva van TCPState. Ez az osztály megduplázza az osztályban meghatározott állapotváltozási interfészt TCPConnection. oldal forrás eredeti webhely

Forrás original.ru

TCPConnection minden állapotfüggő kérést delegál egy állapotban tárolt példányra TCPState. Ráadásul az osztályban TCPConnection műtét van ChangeState, amellyel egy másik objektumra mutató mutatót írhatunk ebbe a változóba TCPState. Osztályépítő TCPConnection inicializálja állapot mutató zárási állapotba TCPCzárva(az alábbiakban definiáljuk). source.ru

oldal forrás eredeti webhely

Minden művelet TCPState példát vesz TCPConnection paraméterként, ezáltal lehetővé téve az objektumot TCPState objektumadatok elérése TCPConnectionés módosítsa a kapcsolat állapotát. .ru

Osztályban TCPState alapértelmezett viselkedést valósított meg az összes rá delegált kérésnél. Megváltoztathatja egy objektum állapotát is TCPConnection a műveleten keresztül ChangeState. TCPState ugyanabban a csomagban található, mint TCPConnection, így ehhez a művelethez is hozzáfér: TCPState . webhely oldal eredeti forrása

source.ru

Az alosztályokban TCPStateállapotfüggő magatartás valósul meg. A TCP-kapcsolat számos állapotban lehet: Alapított(telepítve) hallgat(hallgat), zárva(zárt) stb., és mindegyiknek megvan a maga alosztálya TCPState. Az egyszerűség kedvéért csak 3 alosztályt fogunk részletesen megvizsgálni - A TCPE létrehozva, TCPListenés TCPCzárva. webhely eredeti forrása

eredeti forrás.ru

Az alosztályokban TCPStateállapotfüggő viselkedést valósít meg azon kérések esetében, amelyek az adott állapotban érvényesek. Original.ru forrás

webhely eredeti webhely forrása

Az állapotspecifikus műveletek végrehajtása után ezek a műveletek oldal eredeti forrásoldala

ok ChangeState egy objektum állapotának megváltoztatásához TCPConnection. Ő maga semmilyen információval nem rendelkezik a TCP protokollról. Ezek az alosztályok TCPState meghatározza a protokoll által diktált állapotátmeneteket és műveleteket. webhely oldal eredeti forrása

hu eredeti

Az állapotminta figyelemre méltó felhasználásai

Ralph Johnson és Jonathan Zweig jellemzi az állapotmintát, és leírja a TCP protokollhoz kapcsolódóan.
A legnépszerűbb interaktív rajzprogramok "eszközöket" biztosítanak a közvetlen manipulációs műveletek végrehajtásához. Például egy vonalrajzoló eszköz lehetővé teszi a felhasználó számára, hogy egy tetszőleges pontra kattintson az egérrel, majd húzza az egeret, hogy abból a pontból vonalat húzzon. A kijelölő eszköz lehetővé teszi bizonyos alakzatok kiválasztását. Általában az összes rendelkezésre álló eszköz egy palettán van elhelyezve. A felhasználó feladata egy eszköz kiválasztása és alkalmazása, de a szerkesztő tényleges viselkedése az eszközváltáskor változik: a rajzeszközzel alakzatokat hozunk létre, a kijelölő eszközzel kijelöljük őket, és így tovább. Original.ru forrás

A szerkesztő viselkedésének az aktuális eszköztől való függésének tükrözéséhez használhatja az állapotmintát. webhely oldal eredeti forrása

Meghatározhat egy absztrakt osztályt Eszköz An, amelynek alosztályai eszközspecifikus viselkedést valósítanak meg. A grafikus szerkesztő megőrzi az aktuális objektumra mutató hivatkozást Islés delegálja rá a bejövő kéréseket. Egy eszköz kiválasztásakor a szerkesztő egy másik objektumot használ, ami viselkedésváltozást eredményez. source.ru

Ezt a technikát keretekben használják grafikus szerkesztők HotDraw és Unidraw. Lehetővé teszi az ügyfelek számára, hogy könnyen meghatározhassanak új típusú eszközöket. NÁL NÉL HotDraw Osztály Rajzvezérlőátirányítja a kéréseket az aktuális objektumra Eszköz. NÁL NÉL Unidraw a megfelelő osztályokat nevezzük Nézőés Eszköz. Az alábbi osztálydiagram az osztályinterfészek sematikus ábrázolása Eszköz

oldal forrásoldal eredeti

Az államminta célja

  • Az állapotminta lehetővé teszi az objektum számára, hogy a belső állapota alapján megváltoztassa viselkedését. Úgy tűnik, hogy az objektum megváltoztatta az osztályát.
  • Az állapotminta egy állapotgép objektumorientált megvalósítása.

Probléma megoldás alatt

Egy objektum viselkedése az állapotától függ, és a program végrehajtása során változnia kell. Egy ilyen séma feltételes utasítások halmazának alkalmazásával valósítható meg: az objektum aktuális állapotának elemzése alapján bizonyos műveleteket hajtanak végre. Azonban mikor nagy számok a feltételes utasítások szétszórva lesznek a kódban, és egy ilyen programot nehéz lesz karbantartani.

Államminta megbeszélése

Az állapotminta a következő módon oldja meg ezt a problémát:

  • Bemutatja a Context osztályt, amely interfészt határoz meg a külvilág felé.
  • Bevezeti az absztrakt osztály állapotát.
  • Az állapotgép különböző „állapotait” az állam alosztályaiként reprezentálja.
  • A Context osztálynak van egy mutatója az aktuális állapotra, amely megváltozik, ha az állapotgép állapota megváltozik.

Az állapotminta nem határozza meg, hogy pontosan hol van meghatározva az új állapotba való átmenet feltétele. Két lehetőség van: a Context osztály vagy az állapot alosztályok. Előny utolsó verzió az új származtatott osztályok hozzáadásának egyszerűsége. Hátránya, hogy minden állam alosztálynak ismernie kell a szomszédait, hogy áttérhessen egy új állapotba, ami függőséget vezet be az alosztályok között.

A véges állapotú gépek tervezésére létezik egy alternatív táblázat-orientált megközelítés is, amely egy olyan tábla használatán alapul, amely egyedi módon képezi le a bemeneti adatokat az állapotátmenetekre. Ennek a megközelítésnek azonban vannak hátrányai: nehéz hozzáadni a műveletvégrehajtást az átmenetek végrehajtásakor. Az állapotminta megközelítés kódot használ (adatstruktúrák helyett) az állapotátmenetek végrehajtásához, így ezek a műveletek könnyen hozzáadhatók.

Az államminta szerkezete

A Context osztály külső interfészt határoz meg az ügyfelek számára, és belsőleg tárolja a State objektum aktuális állapotára vonatkozó hivatkozást. Az állapot absztrakt alaposztály interfésze egy kivételével megegyezik a Context interfészével további paraméter- egy mutató a kontextuspéldányra. Az állapotból származó osztályok egy adott állapotra jellemző viselkedést határoznak meg. A Context wrapper osztály az összes beérkezett kérést egy "jelenlegi állapot" objektumhoz delegálja, amely a kapott további paramétert használhatja a Context példány eléréséhez.

Az állapotminta lehetővé teszi az objektum számára, hogy a belső állapota alapján megváltoztassa viselkedését. Hasonló kép figyelhető meg az automata működésében is. A gépek különböző állapotúak lehetnek az áruk elérhetőségétől, a kapott érmék mennyiségétől, a pénzváltás lehetőségétől stb. Miután a vevő kiválasztotta és kifizette az árut, a következő helyzetek (állapotok) lehetségesek:

  • Nem kötelező az árut a vevőnek kiadni, nem kell váltót kiadni.
  • Adja át a vevőnek az árut, és váltson át.
  • A vevő megfelelő pénzösszeg hiányában nem veszi át az árut.
  • A vevő az árut annak hiánya miatt nem veszi át.

Az állapotminta használata

  • Határozzon meg egy meglévőt, vagy hozzon létre egy új "wrapper" környezeti osztályt, amelyet az ügyfél "állapotgépként" fog használni.
  • Hozzon létre egy alapállapot osztályt, amely utánozza a Context osztály interfészét. Mindegyik metódushoz egy további paraméter szükséges: a Context osztály egy példánya. A State osztály bármilyen hasznos "alapértelmezett" viselkedést meghatározhat.
  • Származzon osztályokat az államból az összes lehetséges állapothoz.
  • A "wrapper" osztály Context hivatkozást tartalmaz a "current state" objektumra.
  • A Context osztály egyszerűen delegálja a klienstől kapott összes kérést a "current state" objektumhoz, miközben további paraméterként továbbítja a Context objektum címét.
  • Ezt a címet használva, ha szükséges, a State osztály metódusai megváltoztathatják a Context osztály "aktuális állapotát".

Az állapotminta jellemzői

  • Az állami tárgyak gyakran magányosak.
  • A Flyweight megmutatja, hogyan és mikor oszthatók meg az állapotobjektumok.
  • Az Interpreter minta az állapotot használhatja kontextusok meghatározására elemzéskor.
  • A State és a Bridge minták hasonló felépítésűek, kivéve, hogy a Bridge lehetővé teszi a borítékosztályok hierarchiáját (a "wrapper" osztályok analógjai), míg a State nem. Ezek a minták hasonló szerkezetűek, de eltérő célokat szolgálnak: Az állapot lehetővé teszi az objektum számára, hogy a belső állapot alapján megváltoztassa a viselkedését, míg a Bridge elválasztja az absztrakciót a megvalósítástól, így azok egymástól függetlenül változtathatók.
  • Az államminta megvalósítása a stratégiai mintán alapul. A különbség a céljukban rejlik.

Az államminta megvalósítása

Tekintsünk egy példát egy állapotgépre két lehetséges állapottal és két eseménnyel.

#beleértve névtér használata std; class Machine ( class State *current; public: Machine(); void setCurrent(State *s) ( current = s; ) void on(); void off(); ); osztály Állapot ( public: virtual void on(Machine *m) ( cout<< " already ON\n"; } virtual void off(Machine *m) { cout << " already OFF\n"; } }; void Machine::on() { current->ezen); ) void Machine::off() ( áram->ki(ez); ) osztály BE: nyilvános állapot ( public: ON() ( cout<< " ON-ctor "; }; ~ON() { cout << " dtor-ON\n"; }; void off(Machine *m); }; class OFF: public State { public: OFF() { cout << " OFF-ctor "; }; ~OFF() { cout << " dtor-OFF\n"; }; void on(Machine *m) { cout << " going from OFF to ON"; m->setCurrent(new ON()); törölje ezt; ) ); void ON::off(Machine *m) ( cout<< " going from ON to OFF"; m->setCurrent(new OFF()); törölje ezt; ) Machine::Machine() ( aktuális = new OFF(); cout<< "\n"; } int main() { void(Machine:: *ptrs)() = { Machine::off, Machine::on }; Machine fsm; int num; while (1) { cout << "Enter 0/1: "; cin >>szám; (fsm.*ptrs)(); ) )

Viselkedési tervezési minta. Olyan esetekben használják, amikor a program végrehajtása során az objektumnak állapotától függően meg kell változtatnia viselkedését. A klasszikus megvalósítás magában foglalja egy alap absztrakt osztály vagy interfész létrehozását, amely tartalmazza az összes metódust és egy osztályt minden lehetséges állapothoz. A minta a „feltételes állítások cseréje polimorfizmussal” tanács speciális esete.

Úgy tűnik, hogy minden a könyv szerint van, de van egy árnyalat. Hogyan lehet helyesen megvalósítani az adott állapotra nem releváns módszereket? Például hogyan távolíthatok el egy tételt egy üres kosárból vagy fizethetek ki egy üres kosárért? Általában minden állapotosztály csak a megfelelő metódusokat valósítja meg, egyébként pedig egy InvalidOperationExceptiont dob.

Liskov személy helyettesítésének elvének megsértése. Yaron Minsky alternatív megközelítést javasolt: az illegális államokat képviselhetetlenné tenni. Ez lehetővé teszi a hibaellenőrzés áthelyezését a futási időről a fordítási időre. A vezérlési folyamat azonban ebben az esetben a mintaillesztés alapján lesz megszervezve, nem pedig polimorfizmus felhasználásával. Szerencsére,.

Tudjon meg többet az F# témáról az illegális államokat képviselhetetlenné tenni közzétették Scott Vlashin honlapján.

Tekintsük az „állapot” megvalósítását egy kosár példáján. A C#-ban nincs beépített uniótípus. Külön adat és viselkedés. Magát az állapotot kódoljuk az enum használatával, és a viselkedést külön osztályként. A kényelem kedvéért deklarálunk egy attribútumot, amely összeköti az enumot és a megfelelő viselkedési osztályt, az alap „állapot” osztályt, és hozzáadunk egy kiterjesztési metódust az enumból a viselkedési osztályba való átvitelhez.

Infrastruktúra

public class ÁllapotAttribútum: Attribútum ( public Type StateType ( get; ) public StateAttribute(Type stateType) ( StateType = stateType ?? throw new ArgumentNullException(nameof(stateType)); ) ) public abstract class Állapot ahol T: osztály ( védett állapot(T entitás) ( entitás = entitás ?? dobja új ArgumentNullException(entitás neve); ) védett T Entitás ( get; ) ) public static class StateCodeExtensions ( nyilvános statikus állapot Állítani (ez az Enum stateCode, objektum entitás), ahol T: osztály // igen, igen a tükrözés lassú. Cserélje le fordítási kifejezésfával // vagy IL Emit, és ez gyors lesz => (Állapot ) Activator.CreateInstance(stateCode .GetType() .GetCustomAttribute ().StateType, entitás); )

Tárgykörben

Deklaráljuk a "kosár" entitást:

Nyilvános interfész IHasState ahol TEntity: osztály ( TStateCode StateCode ( get; ) Állapot Állapot ( get; ) ) nyilvános részleges osztály Kosár: IHasState ( public User User ( get; protected set; ) public CartStateCode StateCode ( get; protected set; ) public State Állapot => StateCode.ToState (ez); nyilvános decimális Total ( get; protected set; ) védett virtuális ICollection Termékek ( get; set; ) = új lista (); // Csak ORM védett Kosár() ( ) public Kosár(Felhasználó felhasználó) ( User = user ?? throw new ArgumentNullException(nameof(user)); StateCode = StateCode = CartStateCode.Empty; ) public Cart(User user, IEnumerable Termékek) : this(user) ( StateCode = StateCode = CartStateCode.Empty; foreach (var product in products) ( Products.Add(product); ) ) public Cart(User user, IEnumerable Termékek, decimális összesen) : this(felhasználó, termékek) ( if (összesen<= 0) { throw new ArgumentException(nameof(total)); } Total = total; } }
Valósítsunk meg minden kosárállapothoz egy osztályt: üres, aktív és fizetett, de nem deklarálunk közös felületet. Minden állapot csak a megfelelő viselkedést hajtsa végre. Ez nem jelenti azt, hogy az EmptyCartState , ActiveCartState és PaidCartState osztály nem tudja megvalósítani ugyanazt a felületet. Megtehetik, de egy ilyen interfésznek csak az egyes állapotokban elérhető metódusokat kell tartalmaznia. Esetünkben az Add metódus elérhető az EmptyCartState és az ActiveCartState -en, így az absztrakt AddableCartStateBase-ből örökölhetünk. Termékeket azonban csak kifizetetlen kosárba helyezhet, így nem lesz közös felület minden állam számára. Így garantáljuk az InvalidOperationException hiányát a kódunkban a fordítási szakaszban.

Nyilvános részleges osztály Kosár ( public enum CartStateCode: bájt ( Üres, Aktív, Fizetett ) nyilvános interfész IAddableCartState ( ActiveCartState Add(Termék); IEnumerable Termékek ( get; ) ) nyilvános interfész INotEmptyCartState ( IEnumerable Termékek ( get; ) decimális Összesen ( get; ) ) nyilvános absztrakt osztály AddableCartState: Állapot , IAddableCartState ( védett AddableCartState(Kosár entitás): alap(entitás) ( ) public ActiveCartState Add(Terméktermék) ( Entity.Products.Add(product); Entity.StateCode = CartStateCode.Active; return (ActiveCart).State;StateEnt nyilvános IEnumerálható Termékek => Entitás.Termékek; ) public class EmptyCartState: AddableCartState ( public EmptyCartState(Kosár entitás): alap(entitás) ( ) ) public class ActiveCartState: AddableCartState, INotEmptyCartState ( public ActiveCartState(Kosár entitás): alap(entitás) PayidCart (decimalta) Entity.Total = összesen;Entity.StateCode = CartStateCode.Paid;return (PaidCartState)Entity.State; ) nyilvános állapot Remove(Terméktermék) ( Entity.Products.Remove(product); if(!Entity.Products.Any()) ( Entity.StateCode = CartStateCode.Empty; ) return Entity.State; ) public EmptyCartState Clear() ( Entity. Products.Clear(); Entity.StateCode = KosárÁllamKód.Üres; return (EmptyCartState)Entity.State; ) nyilvános decimális Összesen => Products.Sum(x => x.Price); ) nyilvános osztály PaidCartState: Állam , INotEmptyCartState ( nyilvános IEnumerable Termékek => Entitás.Termékek; nyilvános decimális Összesen => Entitás.Összesen; nyilvános Fizetett kosár állapota(kosár entitás): alap(entitás) ( ) ) )
Az állapotok beágyazottnak vannak nyilvánítva ( beágyazott) osztályok nem véletlenek. A beágyazott osztályok hozzáférhetnek a Cart osztály védett tagjaihoz, ami azt jelenti, hogy nem kell feláldoznunk az entitások beágyazását a viselkedés megvalósítása érdekében. Annak érdekében, hogy az entitásosztály fájlja ne legyen tele, a deklarációt két részre osztottam: Cart.cs és CartStates.cs segítségével. kulcsszó részleges.

Nyilvános ActionResult GetViewResult(State cartState) ( switch (cartState) ( case Cart.ActiveCartState activeState: return View("Active", activeState); case Cart.EmptyCartState emptyState: return View("Empty", emptyState); case Cart.PaidCartState fizetettCartState: return View(" Fizetett", paidCartState); alapértelmezett: új InvalidOperationException(); ) )
A kosár állapotától függően különböző nézeteket használunk. Üres kosár esetén a „Kosara üres” üzenetet jelenítjük meg. Az aktív kosár tartalmazni fogja a termékek listáját, a termékek számának megváltoztatásának és néhány eltávolításának lehetőségét, a „pénztár” gombot és a vásárlás végösszegét.

A fizetett kosár ugyanúgy fog kinézni, mint az aktív, de anélkül, hogy bármit is szerkeszthetne. Ezt a tényt az INotEmptyCartState felület kiemelésével lehet megjegyezni. Így nemcsak a Liskov-helyettesítési elv megsértésétől szabadultunk meg, hanem alkalmaztuk az interfész-elválasztási elvet is.

Következtetés

Az alkalmazáskódban dolgozhatunk az IAddableCartState és INotEmptyCartState interfész hivatkozásokon, hogy újra felhasználhassuk a tételek kosárba tételéért és a kosárban lévő tételek megjelenítéséért felelős kódot. Szerintem a mintaillesztés C#-ban csak akkor alkalmas vezérlési folyamatra, ha nincs semmi közös a típusok között. Más esetekben kényelmesebb az alaphivatkozáson dolgozni. Hasonló technika nem csak egy entitás viselkedésének kódolására alkalmazható, hanem a .

Lehetővé teszi egy objektum számára, hogy a belső állapota alapján változtassa viselkedését. Kívülről úgy tűnik, hogy az objektum osztálya megváltozott.

Az "állapot" minta magában foglalja egy alaposztály vagy interfész hozzárendelését minden érvényes művelethez és egy örököst minden lehetséges állapothoz

Mikor kell használni az állapotmintát

    Mikor kell egy objektum viselkedésének az állapotától függnie, és futás közben dinamikusan változhat

    Ha több feltételes konstrukciót használnak az objektummetódusok kódjában, amelyek kiválasztása az objektum aktuális állapotától függ

Az "állapot" minta UML diagramja:

Az állapotminta megvalósítása C#-ban

Rendszer használata; névtér DoFactory.GangOfFour.State.Structural( /// /// MainApp indítási osztály a Structural számára /// State Design Pattern. /// osztály MainApp( /// /// Belépési pont a konzolalkalmazásba. /// static void Main() ( // Kontextus beállítása állapotban Context c = new Context(new ConcreteStateA()); // Kérések kiadása, amelyek átkapcsolják a c.Request() állapotot; c.Request(); c.Request() ;c.Request(); // Várjon a felhasználóra Console.ReadKey(); ) ) /// Az "állam" absztrakt osztály /// absztrakt osztály Állapot ( public abstract void Handle(Context context); ) /// osztály ConcreteStateA: Állapot ( public override void Handle(Context context) ( context.State = new ConcreteStateB(); ) ) /// "ConcreteState" osztály /// osztály ConcreteStateB: Állapot ( public override void Handle(Context context) ( context.State = new ConcreteStateA(); ) ) /// /// A "Context" osztály /// class Context ( private State _state; // Constructor public Context(State state) ( this.State = állapot; ) // Lekéri vagy beállítja az állapotot public State State ( get ( return _state; ) set ( _state = érték; Console.WriteLine ("State: " + _state.GetType().Name); ) ) public void Request() ( _state.Handle(this); ) ) )

Példa az állammintára a való életből

Példák a .NET-keretrendszerben

  • CommunicationObject valósítja meg állapotgépátmenet a WCF kliens állapotok között: Létrehozva, Megnyitás, Megnyitás, Bezárás, Zárt és Hibás.
  • A Task egy állapotgépet valósít meg a feladatállapotok közötti átmenethez: Létrehozva, WaitingForActivation, WaitingToRun, Futás, Futtatás a befejezésig, Canceled, Faulted.