状态模式
状态模式允许对象内部状态改变的时候改变其行为。状态模式是对象的行为模式。
状态模式就是把对象的状态封装在一个状态对象中,每个状态一个类。
图如下:
抽象的状态角色TcpState封装了一个特定的状态对应的行为;具体状态角色TcpEstablesedSate(已连接状态),TcpListeningSate(监听状态),TcpClosedState(关闭状态)代表了tcp连接的所有状态(模拟),TcpConnection环境类。
Tcp连接环境类TcpConnection中包含了所有的状态,以及连接状态的初始化
package com.headFirst.state;
/**
* LISTEN - 侦听来自远方TCP端口的连接请求;
SYN-SENT -在发送连接请求后等待匹配的连接请求;
SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认;
ESTABLISHED- 代表一个打开的连接,数据可以传送给用户;
FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认;
FIN-WAIT-2 - 从远程TCP等待连接中断请求;
CLOSE-WAIT - 等待从本地用户发来的连接中断请求;
CLOSING -等待远程TCP对连接中断的确认;
LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认;
TIME-WAIT -等待足够的时间以确保远程TCP接收到连接中断请求的确认;
CLOSED - 没有任何连接状态;
============================================================
* 服务器端正常情况下TCP状态迁移:
* CLOSED->LISTEN->SYN收到 ->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
* @author jwt
* @date 2019年9月3日
*/
public class TcpConnection {
private TcpState establisedState;//已连接,代表一个打开的连接,数据可以传送给用户;
private TcpState closedState; //关闭,没有任何连接状态;
private TcpState listeningState; //监听,侦听来自远方TCP端口的连接请求;
private TcpState state;
public TcpConnection() {
establisedState = new TcpEstablisedState(this);
closedState = new TcpClosedState(this);
listeningState = new TcpListeningState(this);
state = closedState;//默认是关闭状态
}
public void open(){
state.open();
}
public void close(){
state.close();
}
public void acknowledge(){
state.acknowledge();
}
public TcpState getEstablisedState() {
return establisedState;
}
public TcpState getClosedState() {
return closedState;
}
public TcpState getListeningState() {
return listeningState;
}
public TcpState getState() {
return state;
}
public void setState(TcpState state) {
this.state = state;
}
}
TcpState封装了一个特定的状态对应的行为
package com.headFirst.state;
public interface TcpState {
void open();
void close();
void acknowledge();
}
具体的状态类
package com.headFirst.state;
public class TcpClosedState implements TcpState {
private TcpConnection connection;
public TcpClosedState(TcpConnection connection){
this.connection = connection;
}
@Override
public void open() {
System.out.println("CLOSED -> LISTEN:开始监听来自远方的tcp连接!");
connection.setState(connection.getListeningState());
}
@Override
public void close() {
}
@Override
public void acknowledge() {
}
}
package com.headFirst.state;
public class TcpEstablisedState implements TcpState {
private TcpConnection tcpConnection;
public TcpEstablisedState(TcpConnection tcpConnection) {
this.tcpConnection = tcpConnection;
}
@Override
public void open() {
}
@Override
public void close() {
System.out.println("ESTABLISHED -> CLOSED:连接已关闭!");
tcpConnection.setState(tcpConnection.getClosedState());
}
@Override
public void acknowledge() {
}
}
package com.headFirst.state;
public class TcpListeningState implements TcpState{
private TcpConnection tcpConnection;
public TcpListeningState(TcpConnection tcpConnection) {
this.tcpConnection = tcpConnection;
}
@Override
public void open() {
}
@Override
public void close() {
}
@Override
public void acknowledge() {
System.out.println("LISTEN->ESTABLISHED:确认,已连接!");
tcpConnection.setState(tcpConnection.getEstablisedState());
}
}
测试结果
package com.headFirst.state;
public class App {
public static void main(String[] args) {
TcpConnection connection = new TcpConnection();
connection.open();//开始监听tcp请求
connection.acknowledge();//已连接
connection.close();//关闭
}
}
状态机
可以看到为每个状态都创建一个类并不太友好,下面使用状态机实现:
package com.headFirst.state.machine;
//CLOSED->LISTEN->SYN收到 ->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED
public enum TcpStateMachine {
//已关闭
CLOSED{
@Override
public TcpStateMachine nextState(){
return LISTEN;
}
@Override
public TcpStateMachine prevState(){
return ESTABLISHED;
}
},
//监听
LISTEN{
@Override
public TcpStateMachine nextState(){
return ESTABLISHED;
}
@Override
public TcpStateMachine prevState(){
return CLOSED;
}
},
//已连接
ESTABLISHED{
@Override
public TcpStateMachine nextState(){
return CLOSED;
}
@Override
public TcpStateMachine prevState(){
return LISTEN;
}
};
public abstract TcpStateMachine nextState();
public abstract TcpStateMachine prevState();
}
package com.headFirst.state.machine;
public class TcpConnection {
private TcpStateMachine stateMachine = TcpStateMachine.CLOSED;
public TcpConnection nextState(){
this.stateMachine = this.stateMachine.nextState();
return this;
}
public void log(){
System.out.println(this.stateMachine.prevState()+"-->"+this.stateMachine.name());
}
}
package com.headFirst.state.machine;
public class App {
public static void main(String[] args) {
TcpConnection conn = new TcpConnection();
conn.nextState();
conn.log();
conn.nextState();
conn.log();
conn.nextState();
conn.log();
conn.nextState();
conn.log();
conn.nextState();
conn.log();
}
}
TcpStateMachine中的CLOSED,LISTEN,ESTABLISHED相当于TcpStateMachine的一个实例,且每个实例都重写了nextState,prevState两个抽象方法,用于指向上一个和下一个状态。
TcpConnection在初始化时默认含有一个Closed的引用,每次调用nextState方法,内部委托TcpStateMachine去转换成下一个状态。