在Java中应用State设计模式

对象的状态由各个属性的当前值构成。当我们调用某个对象的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 PENING = 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();}

“但行好事,莫问前程”,往往成功的几率反而更大些;

在Java中应用State设计模式

相关文章:

你感兴趣的文章:

标签云: