Created
August 25, 2012 08:23
-
-
Save foca/3462441 to your computer and use it in GitHub Desktop.
Stateful is a simple implementation of the State Pattern for JavaScript.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Stateful is a simple implementation of the state pattern for javascript. | |
// | |
// Read more on this design pattern here: | |
// -> http://sourcemaking.com/design_patterns/state | |
// | |
// Initialize Stateful by passing it an object, the name of the initial state | |
// (defaults to "default"), and an optional hash of interfaces that will be | |
// applied for each state. If these interfaces are not passed, they default to | |
// the object's constructor's States property. So, for example: | |
// | |
// Example: | |
// | |
// function TrafficLight() { | |
// this.state = new Stateful(this, "stop"); | |
// } | |
// | |
// TrafficLight.States = { | |
// stop: { | |
// color: "red", | |
// time: 8, | |
// | |
// next: function() { | |
// this.state.transition("go"); | |
// }, | |
// | |
// onEnterState: function() { | |
// // Turn on traffic camera to see who crosses on a red light | |
// }, | |
// | |
// onExitState: function() { | |
// // Turn off traffic camera | |
// } | |
// }, | |
// | |
// go: { | |
// color: "green", | |
// time: 10, | |
// | |
// next: function() { | |
// this.state.transition("caution"); | |
// } | |
// }, | |
// | |
// caution: { | |
// color: "yellow", | |
// time: 2, | |
// | |
// next: function() { | |
// this.state.transition("stop"); | |
// } | |
// } | |
// } | |
// | |
// var light = new TrafficLight(); | |
// light.color //=> "red" | |
// light.next() | |
// light.color //=> "green" | |
// light.next() | |
// light.color //=> "yellow" | |
// light.next() | |
// light.color //=> "red" | |
// | |
// Each state interface can have "special" `onEnterState` / `onExitState` | |
// methods that get called automatically whenever you switch states. | |
// | |
function Stateful(object, initialState, interfaces, onInitialize) { | |
var currentState; | |
this.interfaces = interfaces = interfaces || object.constructor.States; | |
if (typeof interfaces == "undefined") { | |
throw "An object with the set of interfaces for each state is required"; | |
} | |
function trigger() { | |
if (typeof object.trigger == "function") { | |
object.trigger.apply(object, arguments); | |
} | |
} | |
function applyState(state) { | |
var previousInterface = interfaces[currentState]; | |
var newInterface = interfaces[state]; | |
if (typeof newInterface == "undefined") { | |
throw "Invalid state: " + state; | |
} | |
if (previousInterface) { | |
trigger("state:exit", currentState); | |
if (typeof previousInterface.onExitState == "function") { | |
object.onExitState(); | |
} | |
for (property in previousInterface) { | |
delete object[property]; | |
} | |
delete object["onEnterState"]; | |
delete object["onExitState"]; | |
trigger("state:exited", currentState); | |
} | |
trigger("state:enter", state); | |
for (property in newInterface) { | |
object[property] = newInterface[property] | |
} | |
if (typeof newInterface.onEnterState == "function") { | |
object.onEnterState(); | |
} | |
trigger("state:entered", state); | |
} | |
function transitionTo(state) { | |
applyState(state); | |
currentState = state; | |
trigger("state:change"); | |
} | |
function isCurrentState(state) { | |
return currentEvents === state; | |
} | |
if (typeof onInitialize == "function") { | |
onInitialize(this, object); | |
} | |
transitionTo(initialState || "default"); | |
return { | |
is: isCurrentState, | |
transition: transitionTo | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment