状态模式(STATE),别名状态对象(Objects for States),允许一个对象在其内部状态改变时改变它的行为,看起来就像修改了它的类,属于对象行为型模式。状态模式通过将所有与特定状态相关的行为封装到一个或多个状态对象中,当状态改变时,其行为也会随着改变,从而简化大量的条件判断,使代码逻辑更清晰,更易于维护。大千世界,可以看做各个状态的转换。人,生老病死;水,固液气三态转化;天气,阴晴不定。就是这些状态的变换构成了奇妙的世界。玩个游戏都还分低中高级呢,所以状态模式用途大大地。
一、使用场景
1、一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为。俗话说小孩的脸,六月的天,说变就变。他高兴的时候手舞足蹈,伤心的时候大哭大闹,小孩的行为随着心情而改变。
2、一个操作中含有大量的多分支条件语句,且这些分支依赖于该对象的状态。状态模式将这些条件分支封装到多个状态类中,这些类可以独立变化。
3、封装状态转换的规则。状态模式中,各状态之间的转换即可以由状态类自己把握,也可以由环境类控制,集中而不失灵活。
二、UML图
三、Java实现
package study.patterns.state;
/**
* 状态模式:将一个对象在不同状态下的不同行为封装在一个个状态类中,
* 通过设置不同的状态对象可以让环境对象拥有不同的行为,
* 而状态转换的细节对于客户端而言是透明的,方便了客户端的使用。
* @author qbg
* 此处示例由于对TCP协议了解不深,实现不是多恰当,望包涵!
*/
public class StatePattern {
public static void main(String[] args) {
TCPConnection connection = new TCPConnection();
connection.activeOpen();
connection.close();
}
}
/**
* TCP连接,维持一个TCP状态对象,并将请求转发给该对象。
*/
class TCPConnection{
private TCPState state;
/**
* 默认建立的TCP连接是关闭状态
*/
public TCPConnection(){
state = TCPClosed.instance;
}
/**
* 主动发起打开连接请求
*/
public void activeOpen(){
state.activeOpen(this);
}
/**
* 被动接受打开连接请求
*/
public void passiveOpen(){
state.passiveOpen(this);
}
/**
* 关闭连接
*/
public void close(){
state.close(this);
}
/**
* 发送确认码(ACK码)
*/
public void acknowledge(){
state.acknowledge(this);
}
/**
* 发送连接请求
*/
public void send(){
state.send(this);
}
/**
* 改变TCP连接状态
*/
public void changeState(TCPState state){
System.out.println(this.state+" ===> "+state);
this.state = state;
}
/**
* 处理流数据
*/
public void processOCtet(String stream){
System.out.println("传输流数据:"+stream);
}
}
/**
* TCP状态抽象类,定义了状态的公共行为,并针对所有委托给它的请求实现缺省的行为。
*/
abstract class TCPState{
/**
* 传输请求的流数据(包含各种校验码)
*/
public void transmit(TCPConnection connection,String data){}
/**
* 主动发起打开连接请求
*/
public void activeOpen(TCPConnection connection){}
/**
* 被动接受打开连接请求
*/
public void passiveOpen(TCPConnection connection){}
/**
* 关闭连接
*/
public void close(TCPConnection connection){}
/**
* 发送确认码(ACK码)
*/
public void acknowledge(TCPConnection connection){}
/**
* 发送连接请求
*/
public void send(TCPConnection connection){}
/**
* 根据当前状态,改变TCPConnection的TCP连接状态
*/
public void changeState(TCPConnection connection,TCPState state){
connection.changeState(state);
}
}
/**
* TCP连接建立状态,可以传输数据,关闭连接等
*/
class TCPEstablished extends TCPState{
/**
* 无状态类,所以实例可以共享
*/
public static TCPState instance = new TCPEstablished();
@Override
public void transmit(TCPConnection connection, String data) {
connection.processOCtet(data);
}
/**
* 关闭连接并切换状态
*/
@Override
public void close(TCPConnection connection) {
System.out.println("Send FIN,receive ACK of FIN");
changeState(connection, TCPClosed.instance);
}
public String toString(){
return "Established";
}
}
/**
* TCP连接关闭状态,可以打开连接等
*/
class TCPClosed extends TCPState{
/**
* 无状态实例,可以共享
*/
public static TCPState instance = new TCPClosed();
/**
* 主动建立连接,并改变状态
*/
@Override
public void activeOpen(TCPConnection connection) {
System.out.println("Send SYN,receive SYN,ACK,etc.");
changeState(connection, TCPEstablished.instance);
}
/**
* 被动建立连接,并改变状态
*/
@Override
public void passiveOpen(TCPConnection connection) {
changeState(connection, TCPListen.instance);
}
public String toString(){
return "Closed";
}
}
/**
* TCP监听状态,可以发送ACK,SYN,FIN等请求数据
*/
class TCPListen extends TCPState{
public static TCPState instance = new TCPListen();
/**
* 发送请求数据
*/
@Override
public void send(TCPConnection connection) {
changeState(connection, TCPEstablished.instance);
}
public String toString(){
return "Listen";
}
}
运行结果:
Send SYN,receive SYN,ACK,etc.
Closed ===> Established
Send FIN,receive ACK of FIN
Established ===> Closed
四、模式优缺点
优点:
1、将于特定状态相关的行为局部化,并将不同状态的行为分割开来。状态模式将所有与某个特定状态相关的行为封装到一个状态对象中,这样通过添加新的子类可以很容易的增加新的状态和转换。
2、使状态转换显示化。状态模式中不同状态之间的转换是通过切换环境类中的变量来实现的,如TCPConnection类中的TCPState对象引用,而不是为多个变量赋值,这样确保状态转换的原子性,防止环境类Context内部状态不一致现象的发生。
3、State对象可以被共享。对于那些没有内部状态,只有行为的轻量级State对象,各Context对象可以共享一个State对象,从而减少对象的数量。
缺点:
1、由于每个状态对应一个对象,所以会导致系统中类和对象的个数增加。
2、状态模式的设计和实现比较复杂,增加系统的复杂度。