State-machine (конечный автомат, машина состояний)
Вот чуток ссылок для затравочки.
Хабр: тут тоже про стейт-машину есть
Хабр: Простые стейт-машины на службе у разработчика
Вики: Конечный автомат
Простейшая стейт-машина укладывается в один свич-кейс. Более сложная реализация может требовать более серьезного подхода к реализации каждого стейта.
Ну поехали.
Стейт-машина это такая штука, которая нужна если у нас есть объект, поведение которого меняется в зависимости от состояния.
Например самый просто вариант: Лампочка с выключателем.
package { public class Lamp { /** Текущий стейт тру - включено, фолс - выключено. */ private var _state:Boolean; public function Lamp() { _state = false; } /** * Ставим стейт * @param value true - вкл, false - выкл */ public function setState(value:Boolean):void { _state = value; } /** * Геттер стейта * @return */ public function getState():Boolean { return _state; } /** * Если включено светится если выключено не светится. * @return */ public function getLight():int { return _state ? 100 : 0; } } }
Вся соль, показывающая суть стейтмашины у нас в методе: getLight(). Метод у нас один. Но в зависимости от состояния лампочки работает по разному.
Внутри он проверяет текущее состояние и выдает яркость лампочки. Понятно что булевым стейтом код можно упростить, но для демонстрации ок.
Теперь пример чуть посложнее. Например Осадный танк из старкрафта. У него есть тех же два состояния: осада, свернутый.
В осаде у него урон побольше, и не может двигаться. В свернутом виде урон маленький, но он мобильный.
package { public class Tank { public static const STATE_SIEGE:String = "stateSiege"; public static const STATE_TANK:String = "stateTank"; private var _state:String; private var _damage:Number; private var _speed:Number; public function Tank() { setState(STATE_TANK); } public function setState(state:String):String { // Если пытаемся установить состояние которое уже установлено // - просто ничего не делаем. if (state == _state) return _state; switch (state) { case STATE_TANK: _damage = 60; _speed = 20; break; case STATE_SIEGE: _damage = 120; _speed = 0; break; } return _state; } public function getState():String { return _state; } public function getDamage():Number { return _damage; } public function getSpeed():Number { return _speed; } } }
И еще одно важное замечание. В случае с танком не всё так гладко. Описанная машина состояний не предполагает каких-то переходов между стейтами, она статична. Хотя касательно того же танка есть время пока он сворачивается и пока разворачивается. В этот период времени происходит так называемый transition между стейтами. В этот период танк не может ни двигаться ни атаковать.
package { import flash.events.TimerEvent; import flash.utils.Timer; public class Tank { public static const STATE_SIEGE:String = "stateSiege"; public static const STATE_TANK:String = "stateTank"; public static const STATE_TRANSITION:String = "stateNone"; private var _currentState:String; private var _pendingState:String; private var _damage:Number; private var _speed:Number; public function Tank() { setState(STATE_TANK); } public function setState(state:String):void { // Если пытаемся установить состояние которое уже установлено // Либо сейчас происходит транзишн - просто ничего не делаем. if (state == _currentState || _currentState == STATE_TRANSITION) return; _currentState = STATE_TRANSITION; // текущий ставим как транзишн _pendingState = state; // ставим ожидаемый стейт. // Пока происходит транзишн танк ничего не может делать _damage = 0; _speed = 0; // Запускаем транзишн. Для примера обойдемся таймером, // в реальности механизм транзишина может быть сложнее. var timer:Timer = new Timer(1000); timer.addEventListener(TimerEvent.TIMER_COMPLETE, onTransitionComplete); timer.start(); } public function getState():String { return _currentState; } public function getDamage():Number { return _damage; } public function getSpeed():Number { return _speed; } private function onTransitionComplete(event:TimerEvent):void { // По завершении транзишина ставим настройки стейта switch (_pendingState) { case STATE_TANK: _damage = 60; _speed = 20; break; case STATE_SIEGE: _damage = 120; _speed = 0; break; } // Отмечаемся в самих переменных стейтов. _currentState = _pendingState; _pendingState = ""; } } }

Искренне ваш

Всего комментариев 7
Комментарии
![]() ![]() |
|
Апдейтил текст.
|
![]() ![]() |
|
![]() ![]() |
|
Это епик-фейл) спасибо)
|
![]() ![]() |
|
ты с какого времени перешел на Java стайл в написании get\set ?
|
![]() ![]() |
|
Цитата:
Java стайл в написании get\set ?
|
![]() ![]() |
|
Если танк отсюда, то стоило бы ссылку привести.
|
![]() ![]() |
|
Танк не оттуда. Танк оттуда будет в следующей статье. Там более сложная реализация стейтов и уже задействован паттерн стейт. Здесь же простенькое на 20 строк и один класс.
|
Последние записи от Dukobpa3
- Strategy (Стратегия) (27.12.2013)
- State (Состояние) (27.12.2013)
- State-machine (конечный автомат, машина состояний) (25.12.2013)
- Медиатор, Прокси (14.11.2013)
- Инкапсуляция объекта vs инкапсуляция поведения (14.11.2013)