Шаблонът за проектиране е шаблон, който решава често срещан проблем в софтуерния дизайн.

Моделът на състоянието е поведенчески модел, който позволява на обект да промени поведението си, когато вътрешното му състояние се промени.

Тук ще научите как да използвате модела на състояние в TypeScript.

Какво представлява моделът на състоянието?

Моделът на проектиране на състоянието е тясно свързан с крайна машина, която описва програма, която съществува в краен брой състояния във всеки даден момент и се държи различно във всяко състояние.

Има ограничени, предварително определени правила - преходи - които управляват другите състояния, към които всяко състояние може да премине.

За контекст, в онлайн магазин, ако поръчката за пазаруване на клиент е била „доставена“, тя не може да бъде „отменена“, защото вече е била „доставена“. „Доставено“ и „Отменено“ са крайни състояния на поръчката и поръчката ще се държи различно в зависимост от състоянието си.

Държавният модел създава клас за всяко възможно състояние, със специфично за състоянието поведение, съдържащо се във всеки клас.

instagram viewer

Примерно приложение, базирано на състояние

Да приемем например, че създавате приложение, което проследява състоянието на статия за издателска компания. Една статия може или да чака одобрение, да бъде изготвена от писател, редактирана от редактор или публикувана. Това са крайните състояния на статия, която ще бъде публикувана; във всяко уникално състояние статията се държи различно.

Можете да визуализирате различните състояния и преходи на приложението на статията с диаграмата на състоянието по-долу:

Внедрявайки този сценарий в код, първо трябва да декларирате интерфейс за статията:

интерфейсИнтерфейс на статията{
стъпка (): невалиден;
чернова(): невалиден;
редактиране(): невалиден;
публикувам(): невалиден;
}

Този интерфейс ще има всички възможни състояния на приложението.

След това създайте приложение, което прилага всички методи на интерфейса:

// Приложение
класстатияинструментиИнтерфейс на статията{
конструктор() {
това.showCurrentState();
}

частенshowCurrentState(): невалиден{
//...
}

публиченстъпка(): невалиден{
//...
}

публиченчернова(): невалиден{
//...
}

публиченредактиране(): невалиден{
//...
}

публиченпубликувам(): невалиден{
//...
}
}

Частното showCurrentState методът е полезен метод. Този урок го използва, за да покаже какво се случва във всяко състояние. Това не е задължителна част от модела на състоянието.

Обработка на преходи на състояния

След това ще трябва да се справите с преходите на състоянията. Обработването на прехода на състоянието във вашия клас на приложение ще изисква много условни изявления. Това би довело до повтарящ се код, който е по-труден за четене и поддръжка. За да разрешите този проблем, можете да делегирате логиката на прехода за всяко състояние на неговия собствен клас.

Преди да напишете всеки клас на състояние, трябва да създадете абстрактен базов клас, за да сте сигурни, че всеки метод, извикан в невалидно състояние, хвърля грешка.

Например:

абстрактнокласArticleStateинструментиИнтерфейс на статията{
pitch(): ArticleState {
хвърлямновГрешка(„Невалидна операция: Не може да се изпълни задача в сегашно състояние");
}

чернова(): ArticleState {
хвърлямновГрешка(„Невалидна операция: Не може да се изпълни задача в сегашно състояние");
}

edit(): ArticleState {
хвърлямновГрешка(„Невалидна операция: Не може да се изпълни задача в сегашно състояние");
}

публикувай(): ArticleState {
хвърлямновГрешка(„Невалидна операция: Не може да се изпълни задача в сегашно състояние");
}
}

В базовия клас по-горе всеки метод хвърля грешка. Сега трябва да замените всеки метод, като създадете конкретни класове, които се простира основният клас за всяко състояние. Всеки конкретен клас ще съдържа логика, специфична за състоянието.

Всяко приложение има състояние на неактивност, което инициализира приложението. Състоянието на неактивност за това приложение ще настрои приложението на чернова състояние.

Например:

класPendingDraftStateсе простираArticleState{
pitch(): ArticleState {
връщаненов DraftState();
}
}

The стъпка метод в класа по-горе инициализира приложението, като задава текущото състояние на DraftState.

След това заменете останалите методи така:

класDraftStateсе простираArticleState{
чернова(): ArticleState {
връщаненов EditingState();
}
}

Този код заменя чернова метод и връща екземпляр на EditingState.

класEditingStateсе простираArticleState{
edit(): ArticleState {
връщаненов PublishedState();
}
}

Кодовият блок по-горе отменя редактиране метод и връща екземпляр на PublishedState.

класPublishedStateсе простираArticleState{
публикувай(): ArticleState {
връщаненов PendingDraftState();
}
}

Кодовият блок по-горе отменя публикувам метод и връща приложението обратно в неактивно състояние, PendingDraftState.

След това трябва да позволите на приложението да промени състоянието си вътрешно, като посочи текущото състояние чрез частна променлива. Можете да направите това, като инициализирате състоянието на неактивност във вашия клас на приложение и запаметите стойността в частна променлива:

частен състояние: ArticleState = нов PendingDraftState();

След това актуализирайте showCurrentState метод за отпечатване на текущата стойност на състоянието:

частенshowCurrentState(): невалиден{
конзола.log(това.състояние);
}

The showCurrentState метод регистрира текущото състояние на приложението в конзолата.

И накрая, присвоете отново частната променлива към екземпляра на текущото състояние във всеки от методите на вашето приложение.

Например, актуализирайте вашите приложения стъпка метод към кодовия блок по-долу:

публиченстъпка(): невалиден{
това.състояние = това.state.pitch();
това.showCurrentState();
}

В кодовия блок по-горе, стъпка метод променя състоянието от текущото състояние към състоянието на височината.

По същия начин всички други методи ще променят състоянието от текущото състояние на приложението към съответните им състояния.

Актуализирайте методите си на приложение към кодовите блокове по-долу:

The чернова метод:

публиченчернова(): невалиден{
това.състояние = това.state.draft();
това.showCurrentState();
}

The редактиране метод:

публиченредактиране(): невалиден{
това.състояние = това.state.edit();
това.showCurrentState();
}

И на публикувам метод:

публиченпубликувам(): невалиден{
това.състояние = това.state.publish();
това.showCurrentState();
}

Използване на готовото приложение

Вашият готов клас на приложение трябва да бъде подобен на кодовия блок по-долу:

// Приложение
класстатияинструментиИнтерфейс на статията{
частен състояние: ArticleState = нов PendingDraftState();

конструктор() {
това.showCurrentState();
}

частенshowCurrentState(): невалиден{
конзола.log(това.състояние);
}

публиченстъпка(): невалиден{
това.състояние = това.state.pitch();
това.showCurrentState();
}

публиченчернова(): невалиден{
това.състояние = това.state.draft();
това.showCurrentState();
}

публиченредактиране(): невалиден{
това.състояние = това.state.edit();
това.showCurrentState();
}

публиченпубликувам(): невалиден{
това.състояние = това.state.publish();
това.showCurrentState();
}
}

Можете да тествате преходите на състоянията, като извикате методите в правилната последователност. Например:

конст документи = нов член(); // PendingDraftState: {}

docs.pitch(); // DraftState: {}
docs.draft(); // EditingState: {}
docs.edit(); // PublishedState: {}
docs.publish(); // PendingDraftState: {}

Кодовият блок по-горе работи, защото състоянията на приложението се прехвърлиха по подходящ начин.

Ако се опитате да промените състоянието по начин, който не е позволен, например от състояние на височина в състояние на редактиране, приложението ще изведе грешка:

конст документи = нов член(); // PendingDraftState: {}
docs.pitch() // DraftState: {}
docs.edit() // Невалидна операция: Не може да се изпълни задача в текущото състояние

Трябва да използвате този модел само когато:

  • Вие създавате обект, който се държи различно в зависимост от текущото си състояние.
  • Обектът има много състояния.
  • Специфичното за състоянието поведение се променя често.

Предимства и компромиси на държавния модел

Този модел елиминира обемистите условни изрази и поддържа единичната отговорност и отворените/затворените принципи. Но може да е прекалено, ако приложението има малко състояния или неговите състояния не са особено динамични.