A tervezési minta olyan sablon, amely a szoftvertervezés során gyakran ismétlődő problémát oldja meg.

Az állapotminta egy viselkedési minta, amely lehetővé teszi az objektum viselkedésének megváltoztatását, ha belső állapota megváltozik.

Itt megtudhatja, hogyan kell használni az állapotmintát a TypeScriptben.

Mi az az állapotminta?

Az állapottervezési minta szorosan kapcsolódik egy véges állapotú géphez, amely egy olyan programot ír le, amely létezik egy véges állapotok száma egy adott pillanatban, és az egyes állapotokon belül eltérően viselkedik.

Vannak korlátozott, előre meghatározott szabályok – átmenetek –, amelyek szabályozzák a többi állapotot, amelyre az egyes állapotok átválthatnak.

A szövegkörnyezet szempontjából egy online áruházban, ha az ügyfél vásárlási rendelése „kézbesítésre került”, azt nem lehet „törölni”, mert már „kézbesítették”. A „Kézbesítve” és a „Törölve” a megrendelés véges állapotai, és a megrendelés az állapotától függően eltérően fog viselkedni.

Az állapotminta osztályt hoz létre

minden lehetséges állapothoz, az egyes osztályok állapot-specifikus viselkedésével.

Egy példa állapot alapú alkalmazás

Tegyük fel például, hogy egy olyan alkalmazást hoz létre, amely nyomon követi egy kiadó cég cikkének állapotát. Egy cikk jóváhagyásra vár, egy író által megfogalmazott, egy szerkesztő által szerkesztett vagy publikált lehet. Ezek egy publikálandó cikk véges állapotai; minden egyedi állapoton belül a cikk másként viselkedik.

Az alábbi állapotdiagram segítségével megjelenítheti a cikkalkalmazás különböző állapotait és átmeneteit:

Ha ezt a forgatókönyvet kódban implementálja, először deklarálnia kell egy interfészt a cikkhez:

felületCikkfelület{
hangmagasság(): üres;
tervezet(): üres;
edit(): üres;
közzé (): üres;
}

Ezen a felületen az alkalmazás összes lehetséges állapota megtalálható.

Ezután hozzon létre egy alkalmazást, amely megvalósítja az összes interfész metódust:

// Alkalmazás
osztályCikkmegvalósítjaCikkfelület{
konstruktőr() {
ez.showCurrentState();
}

magánshowCurrentState(): üres{
//...
}

nyilvánoshangmagasság(): üres{
//...
}

nyilvánostervezet(): üres{
//...
}

nyilvánosszerkeszteni(): üres{
//...
}

nyilvánosközzé(): üres{
//...
}
}

A magán showCurrentState módszer egy hasznos módszer. Ez az oktatóanyag ennek segítségével mutatja be, mi történik az egyes állapotokban. Ez nem kötelező része az állapotmintának.

Állapotátmenetek kezelése

Ezután kezelnie kell az állapotátmeneteket. Az állapotátmenet kezelése az alkalmazásosztályban sok mindenre lenne szükség feltételes állítások. Ez ismétlődő kódot eredményez, amelyet nehezebb olvasni és karbantartani. A probléma megoldásához delegálhatja az egyes állapotok átmeneti logikáját a saját osztályára.

Az egyes állapotosztályok írása előtt létre kell hoznia egy absztrakt alaposztályt, hogy minden érvénytelen állapotban meghívott metódus hibát okozzon.

Például:

absztraktosztályCikkÁllammegvalósítjaCikkfelület{
pitch(): ArticleState {
dobásújHiba("Érvénytelen művelet: A feladat nem hajtható végre ban ben jelen állapot");
}

tervezet(): CikkÁllam {
dobásújHiba("Érvénytelen művelet: A feladat nem hajtható végre ban ben jelen állapot");
}

edit(): ArticleState {
dobásújHiba("Érvénytelen művelet: A feladat nem hajtható végre ban ben jelen állapot");
}

közzéteszi(): Cikkállapot {
dobásújHiba("Érvénytelen művelet: A feladat nem hajtható végre ban ben jelen állapot");
}
}

A fenti alaposztályban minden metódus hibát ad. Most minden egyes metódust felül kell bírálnia meghatározott osztályok létrehozásával kiterjed az egyes állapotok alaposztálya. Minden egyes osztály állapot-specifikus logikát tartalmaz.

Minden alkalmazásnak van egy tétlen állapota, amely inicializálja az alkalmazást. Az alkalmazás készenléti állapota a következőre állítja az alkalmazást tervezet állapot.

Például:

osztályPending DraftStatekiterjedCikkÁllam{
pitch(): ArticleState {
Visszatérésúj DraftState();
}
}

A hangmagasság metódus a fenti osztályban inicializálja az alkalmazást az aktuális állapot beállításával DraftState.

Ezután írja felül a többi módszert, például:

osztályDraftStatekiterjedCikkÁllam{
tervezet(): CikkÁllam {
Visszatérésúj EditingState();
}
}

Ez a kód felülírja a tervezet metódust, és visszaadja a Szerkesztési állapot.

osztálySzerkesztési állapotkiterjedCikkÁllam{
edit(): ArticleState {
Visszatérésúj PublishedState();
}
}

A fenti kódblokk felülírja a szerkeszteni metódust, és egy példányát adja vissza Published State.

osztályPublished StatekiterjedCikkÁllam{
közzéteszi(): Cikkállapot {
Visszatérésúj PendingDraftState();
}
}

A fenti kódblokk felülírja a közzé módszerrel, és visszaállítja az alkalmazást tétlen állapotba, Pending DraftState.

Ezután engedélyeznie kell az alkalmazásnak, hogy belső változón keresztül módosítsa állapotát az aktuális állapotra való hivatkozással. Ezt úgy teheti meg, hogy inicializálja a tétlen állapotot az alkalmazásosztályon belül, és eltárolja az értéket egy privát változóban:

magán állapot: ArticleState = új PendingDraftState();

Ezután frissítse a showCurrentState módszer az aktuális állapot értékének kinyomtatására:

magánshowCurrentState(): üres{
konzol.log(ez.állapot);
}

A showCurrentState metódus naplózza az alkalmazás aktuális állapotát a konzolon.

Végül rendelje újra a privát változót az aktuális állapotpéldányhoz az alkalmazás minden metódusában.

Például frissítse alkalmazásait hangmagasság módszer az alábbi kódblokkhoz:

nyilvánoshangmagasság(): üres{
ez.state = ez.state.pitch();
ez.showCurrentState();
}

A fenti kódblokkban a hangmagasság metódus megváltoztatja az állapotot az aktuális állapotról a hangmagasság állapotára.

Hasonlóképpen, az összes többi módszer megváltoztatja az állapotot az aktuális alkalmazás állapotáról a megfelelő állapotra.

Frissítse az alkalmazási módszereket az alábbi kódblokkra:

A tervezet módszer:

nyilvánostervezet(): üres{
ez.state = ez.state.draft();
ez.showCurrentState();
}

A szerkeszteni módszer:

nyilvánosszerkeszteni(): üres{
ez.state = ez.state.edit();
ez.showCurrentState();
}

És a közzé módszer:

nyilvánosközzé(): üres{
ez.state = ez.state.publish();
ez.showCurrentState();
}

A kész alkalmazás használata

A kész alkalmazásosztálynak hasonlónak kell lennie az alábbi kódblokkhoz:

// Alkalmazás
osztályCikkmegvalósítjaCikkfelület{
magán állapot: ArticleState = új PendingDraftState();

konstruktőr() {
ez.showCurrentState();
}

magánshowCurrentState(): üres{
konzol.log(ez.állapot);
}

nyilvánoshangmagasság(): üres{
ez.state = ez.state.pitch();
ez.showCurrentState();
}

nyilvánostervezet(): üres{
ez.state = ez.state.draft();
ez.showCurrentState();
}

nyilvánosszerkeszteni(): üres{
ez.state = ez.state.edit();
ez.showCurrentState();
}

nyilvánosközzé(): üres{
ez.state = ez.state.publish();
ez.showCurrentState();
}
}

A metódusok megfelelő sorrendben történő meghívásával tesztelheti az állapotátmeneteket. Például:

const dokumentumok = új Cikk(); // Pending DraftState: {}

docs.pitch(); // Tervezet állapota: {}
docs.draft(); // Szerkesztési állapot: {}
docs.edit(); // PublishedState: {}
docs.publish(); // Pending DraftState: {}

A fenti kódblokk működik, mert az alkalmazás állapotai megfelelően átálltak.

Ha nem megengedett módon próbálja megváltoztatni az állapotot, például a hangmagasság állapotáról a szerkesztési állapotra, az alkalmazás hibát fog kiadni:

const dokumentumok = új Cikk(); // Pending DraftState: {}
docs.pitch() // Tervezet állapota: {}
docs.edit() // Érvénytelen művelet: A jelenlegi állapotban a feladat nem hajtható végre

Csak akkor használja ezt a mintát, ha:

  • Olyan objektumot hoz létre, amely az aktuális állapotától függően eltérően viselkedik.
  • Az objektumnak sok állapota van.
  • Az állapotspecifikus viselkedés gyakran változik.

Az állami minta előnyei és kompromisszumai

Ez a minta kiküszöböli a terjedelmes feltételes kijelentéseket, és fenntartja az egységes felelősséget és a nyitott/zárt elveket. De túlzás lehet, ha az alkalmazásnak kevés állapota van, vagy állapotai nem különösebben dinamikusak.