Suunnittelumalli on malli, joka ratkaisee ohjelmistosuunnittelussa usein toistuvan ongelman.

Tilamalli on käyttäytymismalli, joka antaa objektin muuttaa käyttäytymistään, kun sen sisäinen tila muuttuu.

Täällä opit käyttämään tilamallia TypeScriptissä.

Mikä on valtion malli?

Tilasuunnittelumalli liittyy läheisesti äärellisen tilan koneeseen, joka kuvaa ohjelmaa, joka on olemassa rajallinen useita tiloja kullakin hetkellä ja käyttäytyy eri tavalla kussakin tilassa.

On olemassa rajoitetut, ennalta määrätyt säännöt – siirtymät – jotka hallitsevat muita tiloja, joihin kukin tila voi vaihtaa.

Jos asiakkaan ostotilaus on verkkokaupassa "toimitettu", sitä ei voi "peruuttaa", koska se on jo "toimitettu". "Toimitettu" ja "Peruutettu" ovat tilauksen rajallisia tiloja, ja tilaus käyttäytyy eri tavalla sen tilasta riippuen.

Valtion malli luo luokan jokaiselle mahdolliselle tilalle, ja jokaiseen luokkaan sisältyy tilakohtainen käyttäytyminen.

Esimerkki tilapohjaisesta sovelluksesta

Oletetaan esimerkiksi, että olet luomassa sovellusta, joka seuraa kustantamoyrityksen artikkelin tiloja. Artikkeli voi olla joko hyväksyntää odottava, kirjoittajan laatima, toimittajan muokkaama tai julkaistu. Nämä ovat julkaistavan artikkelin äärelliset tilat; jokaisessa ainutlaatuisessa tilassa artikkeli käyttäytyy eri tavalla.

Voit visualisoida artikkelisovelluksen eri tilat ja siirtymät alla olevan tilakaavion avulla:

Jos tämä skenaario toteutetaan koodissa, sinun on ensin määritettävä artikkelin käyttöliittymä:

käyttöliittymäArtikkelin käyttöliittymä{
piki(): mitätön;
luonnos(): mitätön;
muokata(): mitätön;
julkaista(): mitätön;
}

Tämä käyttöliittymä sisältää kaikki sovelluksen mahdolliset tilat.

Luo seuraavaksi sovellus, joka toteuttaa kaikki käyttöliittymämenetelmät:

// Sovellus
luokkaaArtiklatoteuttaaArtikkelin käyttöliittymä{
rakentaja() {
Tämä.showCurrentState();
}

yksityinennäytä CurrentState(): mitätön{
//...
}

julkinenpiki(): mitätön{
//...
}

julkinenluonnos(): mitätön{
//...
}

julkinenmuokata(): mitätön{
//...
}

julkinenjulkaista(): mitätön{
//...
}
}

Yksityinen näytä CurrentState menetelmä on hyödyllisyysmenetelmä. Tämä opetusohjelma näyttää sen avulla, mitä kussakin osavaltiossa tapahtuu. Se ei ole pakollinen osa tilamallia.

Tilasiirtymien käsittely

Seuraavaksi sinun on käsiteltävä tilasiirtymät. Tilasiirtymän käsitteleminen sovellusluokassasi vaatisi monia ehdolliset lausunnot. Tämä johtaisi toistuvaan koodiin, jota on vaikeampi lukea ja ylläpitää. Voit ratkaista tämän ongelman delegoimalla kunkin tilan siirtymälogiikan omalle luokkalleen.

Ennen kuin kirjoitat kunkin tilaluokan, sinun tulee luoda abstrakti perusluokka varmistaaksesi, että kaikki virheellisessä tilassa kutsutut menetelmät aiheuttavat virheen.

Esimerkiksi:

abstraktiluokkaaArtikkelivaltiototeuttaaArtikkelin käyttöliittymä{
pitch(): Artikkelintila {
heittääUusiVirhe("Virheellinen toiminto: Tehtävää ei voi suorittaa sisään nykyinen tila");
}

luonnos(): Artikkelitila {
heittääUusiVirhe("Virheellinen toiminto: Tehtävää ei voi suorittaa sisään nykyinen tila");
}

edit(): ArticleState {
heittääUusiVirhe("Virheellinen toiminto: Tehtävää ei voi suorittaa sisään nykyinen tila");
}

julkaise(): Artikkelintila {
heittääUusiVirhe("Virheellinen toiminto: Tehtävää ei voi suorittaa sisään nykyinen tila");
}
}

Yllä olevassa perusluokassa jokainen menetelmä antaa virheen. Nyt sinun on ohitettava jokainen menetelmä luomalla tietyt luokat ulottuu kunkin osavaltion perusluokka. Jokainen tietty luokka sisältää tilakohtaisen logiikan.

Jokaisella sovelluksella on valmiustila, joka alustaa sovelluksen. Tämän sovelluksen valmiustila asettaa sovellukselle luonnos osavaltio.

Esimerkiksi:

luokkaaOdottaa DraftStateulottuuArtikkelivaltio{
pitch(): Artikkelintila {
palataUusi Luonnostila();
}
}

The piki menetelmä yllä olevassa luokassa alustaa sovelluksen asettamalla nykyisen tilan Luonnostila.

Ohita seuraavaksi muut menetelmät, kuten näin:

luokkaaLuonnostilaulottuuArtikkelivaltio{
luonnos(): Artikkelitila {
palataUusi EditingState();
}
}

Tämä koodi ohittaa luonnos menetelmä ja palauttaa esiintymän EditingState.

luokkaaEditingStateulottuuArtikkelivaltio{
edit(): ArticleState {
palataUusi JulkaistuState();
}
}

Yllä oleva koodilohko ohittaa muokata menetelmä ja palauttaa esiintymän JulkaistuState.

luokkaaJulkaistuStateulottuuArtikkelivaltio{
julkaise(): Artikkelintila {
palataUusi PendingDraftState();
}
}

Yllä oleva koodilohko ohittaa julkaista menetelmä ja asettaa sovelluksen takaisin lepotilaan, Odottaa DraftState.

Sitten sinun on annettava sovelluksen muuttaa tilaansa sisäisesti viittaamalla nykyiseen tilaan yksityisen muuttujan kautta. Voit tehdä tämän alustamalla lepotilan sovellusluokissasi ja tallentamalla arvon yksityiseen muuttujaan:

yksityinen tila: ArticleState = Uusi PendingDraftState();

Päivitä seuraavaksi näytä CurrentState menetelmä nykyisen tilan arvon tulostamiseen:

yksityinennäytä CurrentState(): mitätön{
konsoli.Hirsi(Tämä.osavaltio);
}

The näytä CurrentState menetelmä kirjaa sovelluksen nykyisen tilan konsoliin.

Määritä lopuksi yksityinen muuttuja uudelleen nykyisen tilan ilmentymään kussakin sovelluksesi menetelmässä.

Päivitä esimerkiksi sovelluksesi piki menetelmä alla olevaan koodilohkoon:

julkinenpiki(): mitätön{
Tämä.state = Tämä.state.pitch();
Tämä.showCurrentState();
}

Yllä olevassa koodilohkossa piki menetelmä muuttaa tilan nykyisestä tilasta äänenkorkeuden tilaan.

Samoin kaikki muut menetelmät muuttavat tilan nykyisestä sovelluksen tilasta vastaaviin tiloihinsa.

Päivitä sovellusmenetelmäsi alla oleviin koodilohkoihin:

The luonnos menetelmä:

julkinenluonnos(): mitätön{
Tämä.state = Tämä.state.draft();
Tämä.showCurrentState();
}

The muokata menetelmä:

julkinenmuokata(): mitätön{
Tämä.state = Tämä.state.edit();
Tämä.showCurrentState();
}

Ja julkaista menetelmä:

julkinenjulkaista(): mitätön{
Tämä.state = Tämä.state.publish();
Tämä.showCurrentState();
}

Valmiin sovelluksen käyttäminen

Valmiin sovellusluokkasi tulee olla samanlainen kuin alla oleva koodilohko:

// Sovellus
luokkaaArtiklatoteuttaaArtikkelin käyttöliittymä{
yksityinen tila: ArticleState = Uusi PendingDraftState();

rakentaja() {
Tämä.showCurrentState();
}

yksityinennäytä CurrentState(): mitätön{
konsoli.Hirsi(Tämä.osavaltio);
}

julkinenpiki(): mitätön{
Tämä.state = Tämä.state.pitch();
Tämä.showCurrentState();
}

julkinenluonnos(): mitätön{
Tämä.state = Tämä.state.draft();
Tämä.showCurrentState();
}

julkinenmuokata(): mitätön{
Tämä.state = Tämä.state.edit();
Tämä.showCurrentState();
}

julkinenjulkaista(): mitätön{
Tämä.state = Tämä.state.publish();
Tämä.showCurrentState();
}
}

Voit testata tilasiirtymiä kutsumalla menetelmiä oikeassa järjestyksessä. Esimerkiksi:

konst asiakirjat = Uusi Artikla(); // Odottaa luonnosta: {}

docs.pitch(); // Luonnostila: {}
docs.draft(); // Muokkaustila: {}
docs.edit(); // JulkaistuState: {}
docs.publish(); // Odottaa luonnosta: {}

Yllä oleva koodilohko toimii, koska sovelluksen tilat siirtyivät asianmukaisesti.

Jos yrität muuttaa tilaa tavalla, joka ei ole sallittua, esimerkiksi äänenkorkeustilasta muokkaustilaan, sovellus antaa virheilmoituksen:

konst asiakirjat = Uusi Artikla(); // Odottaa luonnosta: {}
docs.pitch() // Luonnostila: {}
docs.edit() // Virheellinen toiminto: Tehtävää ei voi suorittaa nykyisessä tilassa

Käytä tätä mallia vain, kun:

  • Olet luomassa objektia, joka käyttäytyy eri tavalla nykyisen tilansa mukaan.
  • Objektilla on monia tiloja.
  • Tilakohtainen käyttäytyminen muuttuu usein.

Valtion mallin edut ja kompromissit

Tämä malli eliminoi kookkaat ehdolliset lausunnot ja säilyttää yhden vastuun ja avoimen/suljetun periaatteen. Mutta se voi olla ylivoimaista, jos sovelluksella on vähän tiloja tai sen tilat eivät ole erityisen dynaamisia.