Образац дизајна је шаблон који решава проблем који се често понавља у дизајну софтвера.
Образац стања је образац понашања који дозвољава објекту да промени своје понашање када се његово унутрашње стање промени.
Овде ћете научити како да користите образац стања у ТипеСцрипт-у.
Шта је државни образац?
Образац дизајна стања је уско повезан са машином коначног стања, која описује програм који постоји у коначан број стања у било ком тренутку и понаша се различито унутар сваке државе.
Постоје ограничена, унапред одређена правила — транзиције — која регулишу друге државе у које свака држава може да пређе.
За контекст, у онлајн продавници, ако је куповна поруџбина „испоручена“, не може се „отказати“ јер је већ „испоручена“. „Испоручено“ и „Отказано“ су коначна стања поруџбине, а наруџба ће се понашати другачије у зависности од свог стања.
Државни образац ствара класу за свако могуће стање, са понашањем специфичним за стање садржаним у свакој класи.
Пример апликације засноване на стању
На пример, претпоставимо да креирате апликацију која прати стања чланка за издавачку компанију. Чланак може чекати на одобрење, израдити га писац, уредити уредник или објављен. Ово су коначна стања чланка који треба да се објави; унутар сваког јединственог стања, чланак се понаша другачије.
Можете да визуализујете различита стања и прелазе у апликацији чланка помоћу дијаграма стања у наставку:
Имплементацијом овог сценарија у коду, прво бисте морали да декларишете интерфејс за чланак:
интерфејсАртицлеИнтерфаце{
висина тона(): празнина;
нацрт(): празнина;
Уредити(): празнина;
објави(): празнина;
}
Овај интерфејс ће имати сва могућа стања апликације.
Затим креирајте апликацију која имплементира све методе интерфејса:
// Апликација
класаЧланакимплементираАртицлеИнтерфаце{
конструктор() {
ово.сховЦуррентСтате();
}приватнисховЦуррентСтате(): празнина{
//...
}јавностивисина тона(): празнина{
//...
}јавностинацрт(): празнина{
//...
}јавностиУредити(): празнина{
//...
}
јавностиобјавити(): празнина{
//...
}
}
Приватни сховЦуррентСтате метода је корисна метода. Овај водич га користи да покаже шта се дешава у свакој држави. То није обавезан део државног обрасца.
Руковање транзицијама стања
Затим ћете морати да обрађујете прелазе стања. Руковање транзицијом стања у вашој класи апликације захтевало би много условни искази. То би резултирало понављајућим кодом који је теже читати и одржавати. Да бисте решили овај проблем, можете делегирати логику транзиције за свако стање у своју класу.
Пре него што напишете сваку класу стања, требало би да креирате апстрактну основну класу да бисте осигурали да било који метод позван у неважећем стању доведе до грешке.
На пример:
апстрактанкласаАртицлеСтатеимплементираАртицлеИнтерфаце{
питцх(): АртицлеСтате {
бацитиНоваГрешка(„Неважећа операција: Није могуће извршити задатак ин тренутно стање");
}драфт(): АртицлеСтате {
бацитиНоваГрешка(„Неважећа операција: Није могуће извршити задатак ин тренутно стање");
}едит(): АртицлеСтате {
бацитиНоваГрешка(„Неважећа операција: Није могуће извршити задатак ин тренутно стање");
}
објави(): АртицлеСтате {
бацитиНоваГрешка(„Неважећа операција: Није могуће извршити задатак ин тренутно стање");
}
}
У основној класи изнад, сваки метод даје грешку. Сада морате да надјачате сваку методу креирањем одређених класа које протеже основна класа за сваку државу. Свака специфична класа ће садржати логику специфичну за стање.
Свака апликација има стање мировања, које иницијализује апликацију. Стање мировања за ову апликацију ће поставити апликацију на нацрт држава.
На пример:
класаПендингДрафтСтатепротежеАртицлеСтате{
питцх(): АртицлеСтате {
повратакНова ДрафтСтате();
}
}
Тхе висина тона метода у класи изнад иницијализује апликацију постављањем тренутног стања на ДрафтСтате.
Затим замените остале методе на следећи начин:
класаДрафтСтатепротежеАртицлеСтате{
драфт(): АртицлеСтате {
повратакНова ЕдитингСтате();
}
}
Овај код замењује нацрт метода и враћа инстанцу ЕдитингСтате.
класаЕдитингСтатепротежеАртицлеСтате{
едит(): АртицлеСтате {
повратакНова ПублисхедСтате();
}
}
Горњи блок кода замењује Уредити метода и враћа инстанцу ПублисхедСтате.
класаПублисхедСтатепротежеАртицлеСтате{
објави(): АртицлеСтате {
повратакНова ПендингДрафтСтате();
}
}
Горњи блок кода замењује објавити метод и враћа апликацију у стање мировања, ПендингДрафтСтате.
Затим морате дозволити апликацији да интерно промени своје стање упућивањем на тренутно стање кроз приватну променљиву. То можете да урадите тако што ћете иницијализовати стање мировања унутар класе апликације и сачувати вредност у приватној променљивој:
приватни стање: АртицлеСтате = Нова ПендингДрафтСтате();
Затим ажурирајте сховЦуррентСтате метод за штампање вредности тренутног стања:
приватнисховЦуррентСтате(): празнина{
конзола.Пријава(ово.држава);
}
Тхе сховЦуррентСтате метод евидентира тренутно стање апликације на конзоли.
На крају, поново доделите приватну променљиву тренутној инстанци стања у свакој од метода ваше апликације.
На пример, ажурирајте своје апликације висина тона метод за блок кода испод:
јавностивисина тона(): празнина{
ово.стате = ово.стате.питцх();
ово.сховЦуррентСтате();
}
У блоку кода изнад, тхе висина тона метода мења стање из тренутног у стање висине.
Слично, све друге методе ће променити стање из тренутног стања апликације у своја одговарајућа стања.
Ажурирајте своје методе апликације на блокове кода у наставку:
Тхе нацрт метод:
јавностинацрт(): празнина{
ово.стате = ово.стате.драфт();
ово.сховЦуррентСтате();
}
Тхе Уредити метод:
јавностиУредити(): празнина{
ово.стате = ово.стате.едит();
ово.сховЦуррентСтате();
}
И тхе објавити метод:
јавностиобјавити(): празнина{
ово.стате = ово.стате.публисх();
ово.сховЦуррентСтате();
}
Коришћење готове апликације
Ваша готова класа апликације треба да буде слична блоку кода испод:
// Апликација
класаЧланакимплементираАртицлеИнтерфаце{
приватни стање: АртицлеСтате = Нова ПендингДрафтСтате();конструктор() {
ово.сховЦуррентСтате();
}приватнисховЦуррентСтате(): празнина{
конзола.Пријава(ово.држава);
}јавностивисина тона(): празнина{
ово.стате = ово.стате.питцх();
ово.сховЦуррентСтате();
}јавностинацрт(): празнина{
ово.стате = ово.стате.драфт();
ово.сховЦуррентСтате();
}јавностиУредити(): празнина{
ово.стате = ово.стате.едит();
ово.сховЦуррентСтате();
}
јавностиобјавити(): празнина{
ово.стате = ово.стате.публисх();
ово.сховЦуррентСтате();
}
}
Можете тестирати прелазе стања позивањем метода у исправном редоследу. На пример:
конст доцс = Нова Чланак(); // ПендингДрафтСтате: {}
доцс.питцх(); // ДрафтСтате: {}
доцс.драфт(); // Стање уређивања: {}
доцс.едит(); // ПублисхедСтате: {}
доцс.публисх(); // ПендингДрафтСтате: {}
Горњи блок кода функционише јер су стања апликације прешла на одговарајући начин.
Ако покушате да промените стање на начин који није дозвољен, на пример, из стања гласа у стање за уређивање, апликација ће приказати грешку:
конст доцс = Нова Чланак(); // ПендингДрафтСтате: {}
доцс.питцх() // ДрафтСтате: {}
доцс.едит() // Неважећа операција: Није могуће извршити задатак у тренутном стању
Овај образац треба да користите само када:
- Правите објекат који се понаша другачије у зависности од његовог тренутног стања.
- Објекат има много стања.
- Понашање специфично за државу се често мења.
Предности и компромиси државног узора
Овај образац елиминише гломазне условне изјаве и одржава јединствену одговорност и отворене/затворене принципе. Али може бити превише ако апликација има неколико стања или њена стања нису посебно динамична.