状态模式 详解

来源:互联网 发布:铁血论坛 知乎 编辑:程序博客网 时间:2024/06/08 00:56

定义

当一个对象在内在状态改变时允许改变其行为,这个对象看起来像是改变了其类;

行为型模式

角色

  • 上下文环境(Context):定义了客户程序需要的接口并维护了一个具体状态角色的实例,将与状态相关的操作委托给当前的Concrete State对象来处理;
  • 抽象状态(State):定义了一个接口以封装使用上下文环境的一个特定状态相关的行为;
  • 具体状态(Concrete State): 实现抽象状态定义的接口;

从网上找到的例图
enter image description here


适用场景

  • 当一个对象的行为取决于它的状态,并且它必须在运行的时候根据状态改变它的行为时;
  • 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态(代码中包含大量与对象状态有关的条件语句);

例子


实现代码

/** * 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();

实现结果:
这里写图片描述


优缺点

  1. 封装了转换原则;
  2. 将所有与某个状态有关的行为放到一个类中,并且可以方便的增加新的状态,只需要改变对象状态即可改变对象的行为;
  3. 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块;
  4. 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数;

注意的是
1. 必然会增加系统类和对象的个数;
2. 结构和实现都较为复杂,如果使用不当将会导致程序结构和代码的混乱;
对“开闭原则”的支持并不太好,对于可以切换状态的的状态模式,增加新的状态类需要修改那些负责状态转换的代码,否则无法切换到新增状态,而且修改某个状态类的行为需要修改对应类的代码;

0 0