状态模式 详解
定义
当一个对象在内在状态改变时允许改变其行为,这个对象看起来像是改变了其类;
行为型模式
角色
- 上下文环境(Context):定义了客户程序需要的接口并维护了一个具体状态角色的实例,将与状态相关的操作委托给当前的Concrete State对象来处理;
- 抽象状态(State):定义了一个接口以封装使用上下文环境的一个特定状态相关的行为;
- 具体状态(Concrete State): 实现抽象状态定义的接口;
从网上找到的例图
适用场景
- 当一个对象的行为取决于它的状态,并且它必须在运行的时候根据状态改变它的行为时;
- 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态(代码中包含大量与对象状态有关的条件语句);
例子
实现代码
/**
* Created by George on 16/7/10.
*/
//电梯状态
function LiftState () {
this._context = null;
this.setContext = function (context) {
this._context = context;
};
// 开门
this.open = function () {
};
// 关门
this.close = function () {
};
// 运行
this.running = function () {
};
// 停止
this.idle = function () {
};
};
//环境类
function Context () {
this._openState = new OpenState();
this._closeState = new CloseState();
this._runningState = new RunningState();
this._idleState = new IdleState();
// 获取和设置状态
this._liftState = new LiftState();
this.getLiftState = function () {
return this._liftState;
};
this.setLiftState = function (state) {
this._liftState = state;
this._liftState.setContext(this);
};
// 更改状态
this.open = function () {
this._liftState.open();
};
this.close = function () {
this._liftState.close();
};
this.running = function () {
this._liftState.running();
};
this.idle = function () {
this._liftState.idle();
};
};
// 具体开门状态
function OpenState () {
};
OpenState.prototype = new LiftState();
OpenState.prototype.close = function () { // 开门后会关闭
this._context.setLiftState(this._context._closeState);
this._context.getLiftState().close();
console.log("open to close");
};
// 关门状态
function CloseState () {
};
CloseState.prototype = new LiftState();
CloseState.prototype.running = function () { // 开门后可能会运行
this._context.setLiftState(this._context._runningState);
this._context.getLiftState().running();
console.log("close to running");
};
CloseState.prototype.idle = function () { // 开门后可能空闲
this._context.setLiftState(this._context._idleState);
this._context.getLiftState().idle();
console.log("close to idle");
};
// 运行状态
function RunningState () {
};
RunningState.prototype = new LiftState();
RunningState.prototype.idle = function () { // 运行后可能会空闲下来
this._context.setLiftState(this._context._idleState);
this._context.getLiftState().idle();
console.log("running to idle");
};
// 空闲状态
function IdleState() {
};
IdleState.prototype = new LiftState();
IdleState.prototype.open = function () { //空闲之后会开门
this._context.setLiftState(this._context._openState);
this._context.getLiftState().open();
console.log("idle to open");
};
// 主函数
var context = new Context();
context.setLiftState(new IdleState());
// 大概操作的意思是先处于限制状态,然后再开门,关上门,然后运行,到达后至于限制,最后开门
context.open();
context.close();
context.running();
context.idle();
context.open();
实现结果:
优缺点
- 封装了转换原则;
- 将所有与某个状态有关的行为放到一个类中,并且可以方便的增加新的状态,只需要改变对象状态即可改变对象的行为;
- 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块;
- 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数;
注意的是
- 必然会增加系统类和对象的个数;
- 结构和实现都较为复杂,如果使用不当将会导致程序结构和代码的混乱;
对“开闭原则”的支持并不太好,对于可以切换状态的的状态模式,增加新的状态类需要修改那些负责状态转换的代码,否则无法切换到新增状态,而且修改某个状态类的行为需要修改对应类的代码;
![](https://i.loli.net/2018/11/17/5beff4d639cbb.jpg)
关注公众号:数据结构与算法那些事儿,每天一篇数据结构与算法