欢迎大家来到IT世界,在知识的湖畔探索吧!
本篇讲解Java设计模式中的状态模式,分为定义、模式应用前案例、结构、模式应用后案例、适用场景、模式可能存在的困惑和本质探讨7个部分。
定义
状态模式允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它所属的类。
在新的分类方式中,状态模式被划分至类属性和行为联动相关需求类别中,其应对的是原有类中多种状态及导致的不同行为的情形。

欢迎大家来到IT世界,在知识的湖畔探索吧!
模式应用前案例
从定义可以看出,状态模式隐含了一个对象可以有多种状态,并且每种状态应该有自身的行为。
学过计算机的同学应该对TCP连接比较熟悉,互联网的底层通信协议主要就是基于TCP。大家应该也对TCP的三次握手有所耳闻。下面,我们就以TCP连接为例,看看未使用状态模式之前的代码实现。
public class TCPConnection {//TCP连接类 private String state; public void setState(String state) { this.state = state; } public void listen(){ if ("LISTEN".equals(this.state)) {// 只有当处于监听状态时才能接受连接 System.out.println("TCP connection is now accepting incoming connections"); }else { System.out.println("TCP connection is not in listening mode, unable to accept incoming connections"); } } public void open() { if ("ESTABLISHED".equals(this.state)) { System.out.println("TCP connection is already established"); } else if ("LISTEN".equals(this.state)) { System.out.println("TCP connection is in listening mode"); // 监听连接请求的逻辑... } else if ("CLOSED".equals(this.state)) { System.out.println("TCP connection has been closed"); } } public void close() { if ("ESTABLISHED".equals(this.state)) { System.out.println("Closing the established TCP connection"); // 关闭已建立连接的逻辑... } else if ("LISTEN".equals(this.state)) { System.out.println("Closing the listening mode of TCP connection"); // 关闭监听模式的逻辑... } else if ("CLOSED".equals(this.state)){ System.out.println("The TCP Connection is already closed"); } } } public class Client {//调用方代码 public static void main(String[] args) { TCPConnection tcpConnection = new TCPConnection(); // 初始状态为 LISTEN tcpConnection.setState("LISTEN"); // 执行监听操作 tcpConnection.listen(); // 改变状态为 ESTABLISHED tcpConnection.setState("ESTABLISHED"); // 执行打开连接操作 tcpConnection.open(); // 改变状态为 CLOSED tcpConnection.setState("CLOSED"); //执行关闭连接操作 tcpConnection.close(); } }
欢迎大家来到IT世界,在知识的湖畔探索吧!
上述代码主要存在两大问题。一是TCPConnection类中包含了各种状态及不同行为的代码,如果后续还需要增加或删除状态,不满足OCP开闭原则。
二是Client类与TCPConnection之间进行状态信息交互时,还需要知晓具体状态的名称以及状态对应的方法名称,对调用方不友好。
结构
状态模式的示例代码实现如下。
欢迎大家来到IT世界,在知识的湖畔探索吧!public class Context { private State state; // 初始化 Context 时设置初始状态 public Context(State state) { this.state = state; } // 设置当前状态 public void setState(State state) { this.state = state; } // 请求处理,委托给当前状态对象 public void request() { state.handle(this); } } public interface State { void handle(Context context); } public class ConcreteStateA implements State { @Override public void handle(Context context) { System.out.println("ConcreteStateA handling the request."); // 在某种条件下,切换到 ConcreteStateB context.setState(new ConcreteStateB()); } } public class ConcreteStateB implements State { @Override public void handle(Context context) { System.out.println("ConcreteStateB handling the request."); // 在某种条件下,切换到 ConcreteStateC context.setState(new ConcreteStateC()); } } public class ConcreteStateC implements State { @Override public void handle(Context context) { System.out.println("ConcreteStateC handling the request."); // 在某种条件下,可以切换回 ConcreteStateA 或其他状态 // context.setState(new ConcreteStateA()); } } public class Client { public static void main(String[] args) { // 创建 Context 对象,并设置初始状态为 ConcreteStateA Context context = new Context(new ConcreteStateA()); // 执行请求,状态对象会根据内部逻辑处理请求,并可能切换状态 context.request(); // 输出 "ConcreteStateA handling the request." // 再次执行请求,由于状态已切换为 ConcreteStateB,因此行为也会改变 context.request(); // 输出 "ConcreteStateB handling the request." // 再次执行请求,由于状态已切换为 ConcreteStateC,因此行为也会改变 context.request(); // 输出 "ConcreteStateC handling the request." } }
从状态模式的结构和示例代码中,状态使用一个家族类来实现。Context核心类与状态家族类的抽象或接口关联,这样后续增加或删除状态都不需要改变Context核心类。
此外,通过状态家族类这种实现方式,可以将不同状态对外的行为都进行统一,对于调用方更加友好。
模式应用后案例
上面TCP连接状态的案例,在使用状态模式后的代码实现如下:
首先,状态抽象成一个家族类实现,包括一个状态接口和三个状态的实现。
public interface ITCPState {//TCP状态接口 abstract void handle(TCPConnection connection); } public class TCPListenState implements ITCPState {//TCPListen状态类 @Override public void handle(TCPConnection connection) { System.out.println( "TP Connection is now accepting incoming connections"); String clientAddress = "192.168.0.1"; int clientPort = 12345; System.out.println("Incoming connection request from: "+clientAddress +":"+clientPort); } } public class TCPEstablishedState implements ITCPState {//TCPEstablished状态类 @Override public void handle(TCPConnection connection) { System.out.println("TCP connection is already established"); } } public class TCPClosedState implements ITCPState {//TCPClosed状态类 @Override public void handle(TCPConnection connection) { System.out.println("The Connection is already closed"); } }
原来TCPConnection大杂烩类简化如下,其中组合了状态家族类中的顶层接口,代码实现如下。
欢迎大家来到IT世界,在知识的湖畔探索吧!public class TCPConnection {//Context上下文类 private ITCPState state; public TCPConnection(ITCPState state) { this.state = state; } public void setState(ITCPState state) { this.state = state; } public void request() { this.state.handle(this); } }
最后,调用方代码实现如下。
public class Client {//调用方代码 public static void main(String[] args) { // 创建TCPConnection对象并设置初始状态为Closed TCPConnection tcpConnection = new TCPConnection(new TCPClosedState()); // 变化状态为 LISTEN tcpConnection.setState(new TCPListenState()); // 执行监听操作 tcpConnection.request(); // 改变状态为 ESTABLISHED tcpConnection.setState(new TCPEstablishedState()); // 执行打开连接操作 tcpConnection.request(); // 改变状态为 CLOSED tcpConnection.setState(new TCPClosedState()); //执行关闭连接操作 tcpConnection.request(); } }
相比原有的实现代码,现在TCPConnection类不会再因为状态的增加、删除而需要一并变更。
其次,Client类不再需要记住交互的细节信息,并且可以通过统一的接口的进行交互。
适用场景
当一个对象在生命周期中会产生多种状态,并且不同的状态下会产生相应的行为时,就应该考虑使用状态模式。
模式可能存在的困惑
困惑1: Context意思上是上下文类,为什么设计模式中会取这样一个名称?
在23个设计模式中,只有解释器模式、策略模式(后面讲到)和状态模式中有Context类。在三个设计模式中,未使用设计模式之前,Context类都是一个大杂烩类,既包括状态也包括不同的行为。
在使用设计模式之后,发现部分或全部核心的行为逻辑都被挪出去,而原来Context类中主要剩下了状态信息,并且这些状态信息成为行为发挥作用时的上下文信息。
困惑2:状态模式与解释器模式的结构非常类似,两者之间有什么区别?
结构上确实很类似,但是细节上有不同。解释器模式的核心是一种状态可以对应多种行为,而状态模式的核心是不同的状态对应不同的行为。
本质
在面向对象程序中,可以认为类是由状态+行为构成的。状态和行为之间可能有不同的关系,比如不同的状态有相同的行为、不同的状态有不同的行为、相同的状态有不同的行为等。状态模式的本质就是提供了一种处理不同状态有不同行为的机制。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/113276.html