1. 概述
The intent of the STATE pattern is to distribute state-specific logic across classes that represent an object’s state.
STATE 设计模式的目的 是:将特定状态相关的逻辑分散到一些类的状态类中。
2. 实例
旋转门: Consider the model of the state of a carousel door(revolving door). A carousel is a large, smart rack that accepts material through a doorway and stores the material according to a bar code ID on it. The door operates with a single button. See the state diagram below for some detail.
旋转门的状态图:(状态图细节见 4. )
3. 状态模型的两种实现方法
3.1 方法一: switch
Observable是java.util中的类^^居然以前都不晓得哦,该打!
Door的具体实现如下:
import java.util.Observable; /** * This class provides an initial model of a carousel door * that manages its state without moving state-specific * logic out to state classes. */ public class Door extends Observable { public final int CLOSED = -1; public final int OPENING = -2; public final int OPEN = -3; public final int CLOSING = -4; public final int STAYOPEN = -5; private int state = CLOSED; /** * The carousel user has touched the carousel button. This "one touch" * button elicits different behaviors, depending on the state of the door. */ public void touch() { switch (state) { case OPENING: case STAYOPEN: setState(CLOSING); break; case CLOSING: case CLOSED: setState(OPENING); break; case OPEN: setState(STAYOPEN); break; default: throw new Error("can't happen"); } } /** * This is a notification from the mechanical carousel that * the door finished opening or shutting. */ public void complete() { if (state == OPENING) setState(OPEN); else if (state == CLOSING) setState(CLOSED); } /** * This is a notification from the mechanical carousel that the * door got tired of being open. */ public void timeout() { setState(CLOSING); } /** * @return a textual description of the door's state */ public String status() { switch (state) { case OPENING: return "Opening"; case OPEN: return "Open"; case CLOSING: return "Closing"; case STAYOPEN: return "StayOpen"; default: return "Closed"; } } private void setState(int state) { this.state = state; setChanged(); notifyObservers(); } }
但是采用这种实现,有一个缺陷:state变量在Door类的实现中浑身扩散,就像癌症一般!
3.2 方法二: State Pattern
A. 基本的 State Pattern 实现
以上设计方式要求每个状态子类实例内部“ hold 住”一个 Door2 实例的引用,这样才能完成 Door2 实例和它的各个状态实例时间的互相通信。这种设计要求一个状态实例对应一个 Door2 实例,这样一来,一个状态实例就只能为一个 Door2 实例服务╮ ( ╯▽╰ ) ╭
客户端这样调用:
public static void main(String[] args){ Door2 door=new Door2(); //1. 初始状态 System.out.println(door.status()); //2. 转移到Opening状态 door.touch(); System.out.println(door.status()); //3. 转移到Open状态 door.complete(); System.out.println(door.status()); //4. 转移到Closing状态 door.timeout(); System.out.println(door.status()); //5. 回到Closed状态 door.complete(); System.out.println(door.status()); }
下面给出Door2类、DoorState抽象类、DoorStayOpen类的实现:
Door2:
public class Door2 extends Observable { public final DoorState CLOSED = new DoorClosed(this); public final DoorState CLOSING = new DoorClosing(this); public final DoorState OPEN = new DoorOpen(this); public final DoorState OPENING = new DoorOpening(this); public final DoorState STAYOPEN = new DoorStayOpen(this); private DoorState state = CLOSED; public void touch() { state.touch(); } public void complete() { state.complete(); } public void timeout() { state.timeout(); } public String status() { return state.status(); } protected void setState(DoorState state) { this.state = state; setChanged(); notifyObservers(); }
DoorState抽象类:
public abstract class DoorState { protected Door2 door; public abstract void touch(); public void complete() { } public void timeout() { } public String status() { String s = getClass().getName(); return s.substring(s.lastIndexOf('.') + 1); } public DoorState(Door2 door) { this.door = door; } }
DoorStayOpen类:
public class DoorStayOpen extends DoorState { public DoorStayOpen(Door2 door) { super(door); } public void touch() { door.setState(door.CLOSING); } }
B. State Pattern 实现 2 ——让状态实例( DoorState 的子类实例)为多个 Door2 实例服务
子状态 DoorOpen 实现转移时只负责返回下目标状态是什么,将状态转移的 action 留给 Door2 实例自己来做;而不是像“ A. 基本的 State Pattern 实现”那样在 DoorOpen 内部保存一个 Door2 实例的引用 door ,亲自调用 door.setState(door.STAYOPEN); 来实现状态转移
改进后的关键代码:
public class DoorOpen extends DoorState{ public DoorState touch(){ return DoorState.STAYOPEN; // 以前是 door.setState(door.STAYOPEN); } ... } public class Door2 extends Observable{ public void touch(){ state=state.touch(); // 以前是 state.touch(); // 即将转移状态的工作留给状态实例来做,事不关己高高挂起 } }
C. State Pattern 实现 3 ——让状态实例( DoorState 的子类实例)为多个 Door2 实例服务
另一种实现这种效果的方法是:将 Door2 实例作为参数传递给 DoorState 的状态转移方法,而非建立 Composite 的关联关系(将 DoorState 的子类对象作为 Door2 的属性)。
也即,用“ Dependency 依赖”(弱依赖,如调用)代替了“ Association 关联”(强依赖,如作为属性进行组合)。
4. 状态图细节
何谓 State 状态 : Generally speaking, the state of an object depends on the collective value of the object ’ s instance variables. In some cases, most of an object ’ s attributes are fairly static once set, and one attribute is dynamic and plays a prominent role in the class ’ s logic. This attribute may represent the state of the entire object and may even be named state.
4.1 State
You can subdivide a state icon into areas that show the state ’ s name and activities 活动 .
3 frequently used categories of activities are entry (what happens when the system enters the state), exit (what happens when the system leaves the state), and do (what happens while the system is in the state).
4.2 Transition s (Details: Event[Guard Condition]/Action)
You can also add some details to the transition lines. You can indicate an event that causes a transition to occur (a trigger event ) and the computation (the action ) that executes and makes the state change happen.
A guard condition : when it’s met, the transition takes place. 通常将超时作为监护条件,∵可以认为此时没有任何 event.
•源状态 Source State :即受转换影响的状态
•目标状态 Target State :当转换完成后,对象的状态
•触发事件 (Trigger) Event :用来为转换定义一个事件,包括调用、改变、信号、时间四类事件
•监护条件 (Guard Condition) :布尔表达式,决定是否激活转换、
•动作 (Action) :转换激活时的操作
几个实例: