岁月联盟 · 中国技术网 本站主页 | 安全认证 | 用户服务 | 技术论坛
新闻快报 | 新手学堂 | 黑客特区 | 程序语言 | 数 据 库 | 防 火 墙 | 路由交换 | 系统集成 | 服 务 器 | 存储备份 | 考试认证
Windows | Linux | Java | 协议分析 | 问题解答 | 进程大全 | 网页设计 | 多 媒 体 | 图库资料 | 软件下载 | 站内下载
  您现在的位置: 岁月联盟 >> Java >> 高级技术 >> 设计模式 >> Java正文
在Java中应用State设计模式
作者:未知 文章来源:本站整理 点击数: 更新时间:2007-7-22 17:49:25

  对象的状态由各个属性的当前值构成。当我们调用某个对象的setXXX()方法时,通常表示修改它的XXX属性。另外,对象在执行方法时,也可能修改自己的状态。在某些情形下,例如建立事务或机器模型时,对象的状态可能是决定其行为的关键因素,依赖于状态的代码逻辑可能遍布于类的大量方法。State模式的目标就是简化这类代码,把依赖于状态的逻辑集中到一组类,每一个类代表一种不同的状态,避免if语句嵌套过深或过于复杂,转而依赖于多态性来调用不同的方法。
  状态模型
  如果对象的状态信息很关键,对象会拥有一些变量来指示如何根据状态做出相应的动作。这些变量大量地散布于复杂的多层嵌套if语句中,来描述对象如何响应可能出现的事件。用这种方式建立对象模型的最大缺点在于if语句可能变得相当复杂一旦要修改对象的状态模型,往往有多个方法的许多if语句需要调整。
  
  以传送带的门为例,考虑其状态变化过程为:传送带的门由单个按钮控制,并且假设初始时处于关闭状态。按一下按钮门开始打开,如果在门完全打开之前再次按下按钮,门开始关闭。一旦门完全打开,它将在2秒延时之后自动开始关闭过程。要禁止门自动关闭,可以在门打开之后按一下按钮。图1描述了传送门的状态变化情况。它是一个UML状态机(State Machine),其中click表示按下按钮的动作。显然,与纯文字描述相比UML状态机图示更加直观易懂。
  
  按照常规的设计思路(不使用State设计模式),在模拟传送带工作过程的软件中,可以使用一个Door1对象代表传送门(如图2所示),状态改变事件由传送带软件发送给Door1对象。
   
  图1 UML状态机
   
  图2 状态改变事件发送给Door1对象
  Door1类从Observable派生,这样客户程序(例如一个GUI程序)就能够方便地了解传送门状态。Door1类首先定义传送门可能处于的状态,代码如下:
  
  public class Door1 extends Observable {
  public static final int CLOSED  = 1;
  public static final int OPENING = 2;
  public static final int OPEN   = 3;
  public static final int CLOSING = 4;
  public static final int STAYOPEN = 5;
  private int state = CLOSED;
  //...
  }
  status()方法返回传送门状态的文字描述,如下所示:
  
  public String status() {
  switch (state) {
    case OPENING :
      return "正在打开";
    case OPEN :
      //...
    default :
      return "已关闭";
  }
  }
  当用户点击传送带的按钮时,传送带程序调用Door1对象的click()方法。click()方法模拟图1所示的状态装换过程:
  
  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);
  }
  }
  Door1类的setState()方法向观察者通知传送门状态改变事件,代码如下:
  
  private void setState(int state) {
  this.state = state;
  setChanged();
  notifyObservers();
  }
  用State模式改造
  Door1类的代码比较复杂,整个类到处都用到了状态变量。如果要比较图1的状态机和Door1类的各个状态变换方法,将是非常困难的,click()方法尤其如此。那么,怎样在这个例子中应用State模式呢?首先要把传送门的各种状态分别定义成类,如图3所示。图3能够更好地与图1的状态机对应。更改后的类设计中,Door2包含了状态机的上下文信息。所谓上下文信息,就是描述环境和一系列其它对象相关的信息。就本例而言,State利用一个上下文对象记录了传送门的当前状态是DoorState类的哪一个实例。
  
  图3 传送门各个状态
  DoorState类的构造函数要求提供一个Door2对象,DoorState的子类利用该对象传达状态变更信息。在这种设计方案中,DoorState的子类通过一个Door2类型的属性绑定到特定的传送门(Door2)对象,因而要求一个DoorState对象只被一个Door2对象引用。同时Door类要把它的状态信息定义成局部变量,代码如下:
  
  public class Door2 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 Door2 door;
  public DoorState(Door2 door) {
    this.door = door;
  }
  public abstract void click();
  public String status() {
    String s = getClass().getName();
    return s.substring(s.lastIndexOf('.') + 1);
  }
   public void complete() { }
   public void timeout() { }
  }
  由上可以看到,现在的status()方法要比修改设计方案之前的status()方法简单多了。新status()方法返回的结果与修改前版本的结果略有不同,它的状态信息从类的名称获得。如果

[1] [2] 下一页


  • 上一个Java:
  • 下一个Java:
  •  
    热门文章
    推荐文章
    关于我们 | 发展历程 | 网站地图 | 广告服务 | 招贤纳士 | 战略合作 | 友情链接 | 著作声明 | 联系我们
    Copyright © 2002-2007 SYUE All rights reserved.
    E_mail:Admin@Syue.Com 皖ICP备05004589号
    未经授权禁止转载、摘编、复制或建立镜像.如有违反,追究法律责任.
    传世私服 传奇世界私服 天龙八部私服 bet365 传世私服 天龙八部私服 热血江湖私服 英雄合击传奇私服 热血江湖私服 bet365 bet365