状态模式

概述

《设计模式》一书中对于 “状态模式” 的描述如下:

允许一个对象在其内部状态发生改变时改变它的行为,使得这个对象看起来像修改了它的类

状态模式的 UML 图如下所示:

state_pattern_uml.png

一般在以下几种情况下使用状态模式:

  • 一个对象的行为取决于它的状态
  • 一个操作中含有庞大的多分支条件语句,且这些分支依赖于该对象的状态

具体示例

一个比较经典的示例就是有关于 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] 《设计模式—可复用面向对象基础》

posted @ 2023-04-16 14:53  FatalFlower  阅读(35)  评论(0编辑  收藏  举报