您现在的位置是:首页 >

23设计模式 详解 在Java中应用State设计模式

火烧 2022-10-03 10:12:38 1042
在Java中应用State设计模式   对象的状态由各个属性的当前值构成 当我们调用某个对象的 etXXX 方法时 通常表示修改它的XXX属性 另外 对象在执行方法时 也可能修改自己的状态 在某些情形

在Java中应用State设计模式  

23设计模式 详解 在Java中应用State设计模式
  对象的状态由各个属性的当前值构成 当我们调用某个对象的setXXX()方法时 通常表示修改它的XXX属性 另外 对象在执行方法时 也可能修改自己的状态 在某些情形下 例如建立事务或机器模型时 对象的状态可能是决定其行为的关键因素 依赖于状态的代码逻辑可能遍布于类的大量方法 State模式的目标就是简化这类代码 把依赖于状态的逻辑集中到一组类 每一个类代表一种不同的状态 避免if语句嵌套过深或过于复杂 转而依赖于多态性来调用不同的方法   状态模型  如果对象的状态信息很关键 对象会拥有一些变量来指示如何根据状态做出相应的动作 这些变量大量地散布于复杂的多层嵌套if语句中 来描述对象如何响应可能出现的事件 用这种方式建立对象模型的最大缺点在于if语句可能变得相当复杂一旦要修改对象的状态模型 往往有多个方法的许多if语句需要调整     以传送带的门为例 考虑其状态变化过程为 传送带的门由单个按钮控制 并且假设初始时处于关闭状态 按一下按钮门开始打开 如果在门完全打开之前再次按下按钮 门开始关闭 一旦门完全打开 它将在 秒延时之后自动开始关闭过程 要禁止门自动关闭 可以在门打开之后按一下按钮 图 描述了传送门的状态变化情况 它是一个UML状态机(State Machine) 其中click表示按下按钮的动作 显然 与纯文字描述相比UML状态机图示更加直观易懂     按照常规的设计思路(不使用State设计模式) 在模拟传送带工作过程的软件中 可以使用一个Door 对象代表传送门(如图 所示) 状态改变事件由传送带软件发送给Door 对象       图 UML状态机      图 状态改变事件发送给Door 对象  Door 类从Observable派生 这样客户程序(例如一个GUI程序)就能够方便地了解传送门状态 Door 类首先定义传送门可能处于的状态 代码如下     public class Door extends Observable {  public static final int CLOSED  = ;  public static final int OPENING = ;  public static final int OPEN   = ;   public static final int CLOSING = ;  public static final int STAYOPEN = ;   private int state = CLOSED;  //   }  status()方法返回传送门状态的文字描述 如下所示     public String status() {  switch (state) {    case OPENING :      return "正在打开";    case OPEN :      //     default :      return "已关闭";  }  }  当用户点击传送带的按钮时 传送带程序调用Door 对象的click()方法 click()方法模拟图 所示的状态装换过程     public void click() {  if (state == CLOSED) {    setState(OPENING);  }   else if (state == OPENING || state == STAYOPEN) {    setState(CLOSING);  }   else if (state == OPEN) {    setState(STAYOPEN);  }   else if (state == CLOSING) {    setState(OPENING);  }  }  Door 类的setState()方法向观察者通知传送门状态改变事件 代码如下     private void setState(int state) {  this state = state;  setChanged();  notifyObservers();  }  用State模式改造  Door 类的代码比较复杂 整个类到处都用到了状态变量 如果要比较图 的状态机和Door 类的各个状态变换方法 将是非常困难的 click()方法尤其如此 那么 怎样在这个例子中应用State模式呢?首先要把传送门的各种状态分别定义成类 如图 所示 图 能够更好地与图 的状态机对应 更改后的类设计中 Door 包含了状态机的上下文信息 所谓上下文信息 就是描述环境和一系列其它对象相关的信息 就本例而言 State利用一个上下文对象记录了传送门的当前状态是DoorState类的哪一个实例      图 传送门各个状态  DoorState类的构造函数要求提供一个Door 对象 DoorState的子类利用该对象传达状态变更信息 在这种设计方案中 DoorState的子类通过一个Door 类型的属性绑定到特定的传送门(Door )对象 因而要求一个DoorState对象只被一个Door 对象引用 同时Door类要把它的状态信息定义成局部变量 代码如下     public class Door extends Observable {  public final DoorState CLOSED  = new DoorClosed(this);  // 按照类似方式定义DoorState类型的  // OPENING OPEN CLOSING STAYOPEN对象(略)  private DoorState state = CLOSED;  //   }  DoorState类是一个抽象类 由子类实现其click()方法 在状态机中 每一个状态均有相应的 按下按钮 操作 修改后的设计中每一个描述状态的类也有一个click()方法 两者是一致的 DoorState类处理了其它可能的变换 所以DoorState的子类可以忽略无关的事件 代码如下     public abstract class DoorState {  protected Door door;  public DoorState(Door door) {    this door = door;  }  public abstract void click();  public String status() {    String s = getClass() getName();    return s substring(s lastIndexOf( ) + );  }   public void plete() { }   public void timeout() { }  }  由上可以看到 现在的status()方法要比修改设计方案之前的status()方法简单多了 新status()方法返回的结果与修改前版本的结果略有不同 它的状态信息从类的名称获得 如果要返回修改设计方案之前的信息 只需把这些状态信息分别记录到DoorState的各个子类中 然后在这个status()方法中直接提取即可     新的设计方案中 传送门对象(Door )从传送带接收状态改变信息的这一角色仍未改变 但现在Door 对象只需把这些状态改变信息直接传递给当前的状态对象就可以了 代码如下     public class Door extends Observable {  // 声明变量  protected void setState(DoorState state) {    this state = state;    setChanged();    notifyObservers();  }  public void click() {    state click();  }  // plete() status() timeout()都直接  // 调用state的相应方法即可(略)  }  这里的click() plete() status()和timeout()方法体现了Java类多态性的应用 所有这些方法都起著判断和选择动作的作用 即是虽然每一个方法的代码是不含if判断逻辑的 但实际运行时被调用的状态对象却不断变化 在调用click()时会发生哪些事情呢?按照多态性规则 答案依赖于当时传送门的状态 修改后的代码有效地担负起了根据状态执行不同动作的任务 但由于利用了多态性 它变得更加简单了     Door 类中的setState()方法现在由DoorState的子类调用 这些DoorState的子类与图 状态机中的相应实体很相似 例如 状态机中Open状态包含Timeout和Click DoorOpen类则包含两个对应的方法timeout()和click() DoorOpen类的代码如下     public class DoorOpen extends DoorState {  public DoorOpen(Door door) {    super(door);  }  public void click() {    door setState(door STAYOPEN);  }  public void timeout() {    door setState(door CLOSING);  }  }  从上面可以看到 利用State设计模式之后 代码变得更简单了 不过 细心的读者或许已经注意到 Door 类用到的 常量 实际上是变量 这给人一种不规范的感觉 假设现在要把这些状态常量移到_DoorConstant接口 这就需要从DoorState类消除Door 实例变量 修改办法是 重新定义DoorState类中的click() plete()和timeout()变换方法 把一个Door 对象以参数的形式传递给它们 按照这种设计方法 Door 对象调用状态变换方法 例如click()时 将采用state click(this)的形式                  lishixinzhi/Article/program/Java/gj/201311/27535  
永远跟党走
  • 如果你觉得本站很棒,可以通过扫码支付打赏哦!

    • 微信收款码
    • 支付宝收款码