Uzorak dizajna je predložak koji rješava problem koji se često ponavlja u dizajnu softvera.

Uzorak stanja je obrazac ponašanja koji omogućuje objektu da promijeni svoje ponašanje kada se promijeni njegovo unutarnje stanje.

Ovdje ćete naučiti kako koristiti obrazac stanja u TypeScriptu.

Što je obrazac stanja?

Uzorak dizajna stanja usko je povezan s konačnim strojem, koji opisuje program koji postoji u konačan broj stanja u bilo kojem trenutku i ponaša se drugačije unutar svakog stanja.

Postoje ograničena, unaprijed određena pravila - prijelazi - koja upravljaju ostalim državama u koje se svaka država može prebaciti.

U kontekstu, u internetskoj trgovini, ako je kupčeva narudžba za kupnju "isporučena", ne može se "otkazati" jer je već "isporučena". "Isporučeno" i "Otkazano" su konačna stanja narudžbe, a narudžba će se ponašati drugačije ovisno o svom stanju.

Državni obrazac stvara klasu za svako moguće stanje, s ponašanjem specifičnim za stanje sadržanim u svakoj klasi.

Primjer aplikacije temeljene na stanju

Na primjer, pretpostavimo da stvarate aplikaciju koja prati stanja članka za izdavačku tvrtku. Članak može čekati odobrenje, može ga izraditi pisac, urediti urednik ili može biti objavljen. Ovo su konačna stanja članka koji će biti objavljen; unutar svakog jedinstvenog stanja, članak se ponaša drugačije.

Možete vizualizirati različita stanja i prijelaze aplikacije članka pomoću dijagrama stanja u nastavku:

Implementirajući ovaj scenarij u kodu, prvo biste morali deklarirati sučelje za članak:

sučeljeSučelje članka{
nagib(): poništiti;
Nacrt(): poništiti;
Uredi(): poništiti;
objaviti(): poništiti;
}

Ovo sučelje će imati sva moguća stanja aplikacije.

Zatim izradite aplikaciju koja implementira sve metode sučelja:

// Primjena
razredaČlanakoruđaSučelje članka{
konstruktor() {
ovaj.showCurrentState();
}

privatnashowCurrentState(): poništiti{
//...
}

javnostnagib(): poništiti{
//...
}

javnostNacrt(): poništiti{
//...
}

javnostUredi(): poništiti{
//...
}

javnostobjaviti(): poništiti{
//...
}
}

Privatno showCurrentState metoda je korisna metoda. Ovaj vodič ga koristi da pokaže što se događa u svakoj državi. To nije obavezni dio obrasca stanja.

Rukovanje prijelazima stanja

Zatim ćete morati rukovati prijelazima stanja. Rukovanje prijelazom stanja u vašoj aplikacijskoj klasi zahtijevalo bi mnogo uvjetne izjave. To bi rezultiralo ponavljajućim kodom koji je teže čitati i održavati. Da biste riješili ovaj problem, možete delegirati logiku prijelaza za svako stanje u njegovu vlastitu klasu.

Prije nego što napišete svaku klasu stanja, trebali biste stvoriti apstraktnu osnovnu klasu kako biste bili sigurni da svaka metoda pozvana u nevažećem stanju izbacuje pogrešku.

Na primjer:

sažetakrazredaČlanakStateoruđaSučelje članka{
pitch(): ArticleState {
bacanjenoviGreška("Nevažeća operacija: Nije moguće izvršiti zadatak u Trenutna država");
}

nacrt(): ArticleState {
bacanjenoviGreška("Nevažeća operacija: Nije moguće izvršiti zadatak u Trenutna država");
}

edit(): ArticleState {
bacanjenoviGreška("Nevažeća operacija: Nije moguće izvršiti zadatak u Trenutna država");
}

objavi(): ArticleState {
bacanjenoviGreška("Nevažeća operacija: Nije moguće izvršiti zadatak u Trenutna država");
}
}

U gornjoj osnovnoj klasi svaka metoda daje pogrešku. Sada morate nadjačati svaku metodu stvaranjem specifičnih klasa koje proteže se osnovna klasa za svaku državu. Svaka specifična klasa će sadržavati logiku specifičnu za stanje.

Svaka aplikacija ima stanje mirovanja, koje inicijalizira aplikaciju. Stanje mirovanja za ovu aplikaciju će postaviti aplikaciju na Nacrt država.

Na primjer:

razredaPendingDraftStateproteže seČlanakState{
pitch(): ArticleState {
povrataknovi DraftState();
}
}

The nagib metoda u gornjoj klasi inicijalizira aplikaciju postavljanjem trenutnog stanja na DraftState.

Zatim nadjačajte ostale metode ovako:

razredaDraftStateproteže seČlanakState{
nacrt(): ArticleState {
povrataknovi Stanje uređivanja();
}
}

Ovaj kod nadjačava Nacrt metoda i vraća instancu EditingState.

razredaEditingStateproteže seČlanakState{
edit(): ArticleState {
povrataknovi PublishedState();
}
}

Gornji blok koda nadjačava Uredi metoda i vraća instancu od PublishedState.

razredaPublishedStateproteže seČlanakState{
objavi(): ArticleState {
povrataknovi PendingDraftState();
}
}

Gornji blok koda nadjačava objaviti metodu i vraća aplikaciju u stanje mirovanja, PendingDraftState.

Zatim morate dopustiti aplikaciji da interno promijeni svoje stanje pozivanjem na trenutno stanje putem privatne varijable. To možete učiniti tako da inicijalizirate stanje mirovanja unutar svoje klase aplikacije i pohranite vrijednost u privatnu varijablu:

privatna stanje: ArticleState = novi PendingDraftState();

Zatim ažurirajte showCurrentState metoda ispisa trenutne vrijednosti stanja:

privatnashowCurrentState(): poništiti{
konzola.log(ovaj.država);
}

The showCurrentState metoda zapisuje trenutno stanje aplikacije na konzolu.

Na kraju, ponovno dodijelite privatnu varijablu trenutnoj instanci stanja u svakoj od metoda vaše aplikacije.

Na primjer, ažurirajte svoje aplikacije nagib metodu u blok koda u nastavku:

javnostnagib(): poništiti{
ovaj.stanje = ovaj.state.pitch();
ovaj.showCurrentState();
}

U gornjem bloku koda, nagib metoda mijenja stanje iz trenutnog stanja u stanje visine tona.

Slično, sve druge metode će promijeniti stanje iz trenutnog stanja aplikacije u svoja odgovarajuća stanja.

Ažurirajte svoje metode primjene na donje blokove koda:

The Nacrt metoda:

javnostNacrt(): poništiti{
ovaj.stanje = ovaj.state.draft();
ovaj.showCurrentState();
}

The Uredi metoda:

javnostUredi(): poništiti{
ovaj.stanje = ovaj.state.edit();
ovaj.showCurrentState();
}

i objaviti metoda:

javnostobjaviti(): poništiti{
ovaj.stanje = ovaj.state.publish();
ovaj.showCurrentState();
}

Korištenje gotove aplikacije

Vaša gotova klasa aplikacije trebala bi biti slična donjem bloku koda:

// Primjena
razredaČlanakoruđaSučelje članka{
privatna stanje: ArticleState = novi PendingDraftState();

konstruktor() {
ovaj.showCurrentState();
}

privatnashowCurrentState(): poništiti{
konzola.log(ovaj.država);
}

javnostnagib(): poništiti{
ovaj.stanje = ovaj.state.pitch();
ovaj.showCurrentState();
}

javnostNacrt(): poništiti{
ovaj.stanje = ovaj.state.draft();
ovaj.showCurrentState();
}

javnostUredi(): poništiti{
ovaj.stanje = ovaj.state.edit();
ovaj.showCurrentState();
}

javnostobjaviti(): poništiti{
ovaj.stanje = ovaj.state.publish();
ovaj.showCurrentState();
}
}

Prijelaze stanja možete testirati pozivanjem metoda u ispravnom nizu. Na primjer:

konst dokumenti = novi Članak(); // PendingDraftState: {}

docs.pitch(); // DraftState: {}
dokumenti.nacrt(); // EditingState: {}
docs.edit(); // PublishedState: {}
dokumenti.objavi(); // PendingDraftState: {}

Gornji blok koda radi jer su stanja aplikacije prošla na odgovarajući način.

Ako pokušate promijeniti stanje na način koji nije dopušten, na primjer, iz stanja visine u stanje uređivanja, aplikacija će izbaciti pogrešku:

konst dokumenti = novi Članak(); // PendingDraftState: {}
docs.pitch() // DraftState: {}
docs.edit() // Nevažeća operacija: Ne može izvršiti zadatak u trenutnom stanju

Ovaj obrazac biste trebali koristiti samo kada:

  • Stvarate objekt koji se ponaša drugačije ovisno o trenutnom stanju.
  • Objekt ima mnogo stanja.
  • Ponašanje specifično za stanje često se mijenja.

Prednosti i nedostaci obrasca stanja

Ovaj obrazac eliminira glomazne uvjetne izjave i održava jedinstvenu odgovornost i načela otvorenog/zatvorenog. Ali može biti pretjerano ako aplikacija ima nekoliko stanja ili njezina stanja nisu posebno dinamična.