状态模式
概述
《设计模式》一书中对于 “状态模式” 的描述如下:
允许一个对象在其内部状态发生改变时改变它的行为,使得这个对象看起来像修改了它的类
状态模式的 UML 图如下所示:
一般在以下几种情况下使用状态模式:
- 一个对象的行为取决于它的状态
- 一个操作中含有庞大的多分支条件语句,且这些分支依赖于该对象的状态
具体示例
一个比较经典的示例就是有关于 TCP 连接的处理,对于一个 TCP 连接来讲,在不同的连接状态下,需要进行的处理是不同的。比如,如果是未建立连接的状态下需要发送数据,那么首先需要建立连接;如果在已经建立连接的前提条件下,那么只需要直接发送数据即可,这种情况的处理就很适合使用状态模式进行处理
首先,定义所有不同状态下进行处理的抽象类 TCPState
:
public abstract class TCPState {
public abstract void openConnection();
public abstract void sendMsg();
public abstract void close();
}
之后,对于 TCPConnection
连接对象来讲,需要将对应的处理委托给实际的状态进行处理:
public class TCPConnection {
private TCPState state;
public void changeState(TCPState state) {
this.state = state;
}
public void openConnection() {
this.state.openConnection();
}
public void sendMsg() {
this.state.sendMsg();
}
public void close() {
this.state.close();
}
}
对于不同的连接状态,需要执行不同的处理:
public class EmptyState extends TCPState { // 未建立连接时的有关处理
@Override
public void openConnection() {
createConnection(); // 实际创建连接的过程
}
@Override
public void sendMsg() {
throw new IllegalStateException("当前未创建对应的 TCP 连接");
}
@Override
public void close() {
throw new IllegalStateException("当前未创建对应的 TCP 连接");
}
}
public class EstablishState extends TCPState { // 已经建立连接时的有关处理
@Override
public void openConnection() {
throw new IllegalStateException("不能重复打开已有的连接");
}
@Override
public void sendMsg() {
sendMessage(); // 发送数据的具体处理
}
@Override
public void close() {
closeConnection(); // 具体的关闭连接处理
}
}
而对于 TCPConnection
对象来讲,现在只需要再维护一个对应的状态机,来处理状态之间的转换即可:
public class Application {
public static void main(String[] args) {
TCPConnection conn = new TCPConnection();
conn.changeState(new EmptyState());
conn.openConnection();
// 创建连接结束
conn.changeState(new EstablishState());
conn.sendMsg("Hello World!");
conn.close();
}
}
总结
通过状态模式,可以简化一些冗余的判断处理,加强代码的结构性以及降低对象之间的耦合关系。在涉及到状态之间的转换时,可以通过预先定义对应的状态机来确定每一次操作后的所属状态,从而加强对象的复用
参考:
[1] 《设计模式—可复用面向对象基础》