Java设计模式之行为型-状态模式(UML类图+案例分析)

news/2025/3/15 1:25:26/

目录

一、基础概念

二、UML类图

三、角色设计

四、案例分析

五、总结


一、基础概念

状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类,状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。

二、UML类图

三、角色设计

角色描述
环境角色维护一个State的实例,用来表示当前状态。并且定义了状态转换的set方法以及请求处理的业务方法。
抽象状态角色定义一个接口封装与环境角色的一个特点接口相关行为
具体状态角色实现抽象状态接口,封装状态对应的行为

四、案例分析

下面案例通过状态模式模拟了一个电梯系统,电梯在开门、关门、运行、停止不同状态下的行为逻辑,以及在客户端调用之间状态的转变。

定义了电梯状态的抽象接口,包含开门、关门、运行、停止等操作。这对应状态模式中的抽象状态角色:

public interface LiftState {/*** 设置环境变量* @param context*/public void setContext(Context context);/*** 电梯开启操作*/public void open();/*** 电梯关闭操作*/public void close();/*** 电梯运行操作*/public void run();/*** 电梯停止操作*/public void stop();
}

实现了LiftState接口,作为具体状态类,封装了对应的状态下电梯的行为逻辑。这对应具体状态角色:

public class OpeningState implements LiftState {private Context context;@Overridepublic void setContext(Context context) {this.context = context;}@Overridepublic void open() {//电梯门是打开的,不操作System.out.println("电梯门已打开.....");}@Overridepublic void close() {//电梯门打开,可以执行关闭操作this.context.setLiftState(Context.CLOSING_STATE);this.context.close();}@Overridepublic void run() {//电梯开门的时候不可以运行}@Overridepublic void stop() {//电梯能开门必须是停下的}
}public class ClosingState implements LiftState {private Context context;@Overridepublic void setContext(Context context) {this.context = context;}@Overridepublic void open() {//关门状态下可以开门this.context.setLiftState(Context.OPENING_STATE);this.context.open();}@Overridepublic void close() {//已经时关门状态,无需关门操作System.out.println("电梯门关闭.....");}@Overridepublic void run() {//关了门自然可以运行this.context.setLiftState(Context.RUNNING_STATE);this.context.run();}@Overridepublic void stop() {//电梯门关了但我不按楼层this.context.setLiftState(Context.CLOSING_STATE);this.context.stop();}
}public class RunningState implements LiftState {private Context context;@Overridepublic void setContext(Context context) {this.context = context;}@Overridepublic void open() {//运行状态下不可开门}@Overridepublic void close() {//运行状态下已经是关好门的}@Overridepublic void run() {//正在运行,无需操作System.out.println("电梯正在运行.......");}@Overridepublic void stop() {//运行可停下this.context.setLiftState(Context.STOPPING_STATE);this.context.stop();}
}public class StoppingState implements LiftState {private Context context;@Overridepublic void setContext(Context context) {this.context = context;}@Overridepublic void open() {//停下的状态时可以开门的this.context.setLiftState(Context.OPENING_STATE);this.context.open();}@Overridepublic void close() {//停下的时候已经是关了门的}@Overridepublic void run() {//停下也可以继续运行this.context.setLiftState(Context.RUNNING_STATE);this.context.run();}@Overridepublic void stop() {//已经停下无需操作System.out.println("电梯停止.......");}
}

维护当前状态,提供请求委托和状态切换方法,对应的是环境角色:


public class Context {//定义状态对象常量public final static OpeningState OPENING_STATE = new OpeningState();public final static ClosingState CLOSING_STATE = new ClosingState();public final static RunningState RUNNING_STATE = new RunningState();public final static StoppingState STOPPING_STATE = new StoppingState();//定义当前电梯状态变量private LiftState liftState;public void setLiftState(LiftState liftState) {this.liftState = liftState;//将当前对象作为参数传递到状态对象的环境中this.liftState.setContext(this);}//定义电梯的四个方法public void open(){this.liftState.open();}public void close(){this.liftState.close();}public void run(){this.liftState.run();}public void stop(){this.liftState.stop();}
}

客户端:

public class Client {public static void main(String[] args) {Context context = new Context();context.setLiftState(new RunningState());context.open(); context.close();context.run();context.stop();}}

运行结果如下:

执行流程如下:

1、Client调用Context的开门、运行接口。

2、Context委托请求给当前的状态对象。

3、状态对象执行状态对应的行为,如果需要转变状态,则调用Context切换状态。

4、Context切换状态变量到新状态,新的状态对象成为当前活动状态5. 新的状态对象接受请求,执行相应行为

综上,状态对象封装行为,Context维护状态,Client只与Context交互,这样将状态转移逻辑聚合到状态对象中,实现了与Context的解耦。

状态模式很好地封装了状态切换逻辑,消除了庞大的条件分支语句,提供了可维护的状态机。 

五、总结

优点:

1、封装了状态转换逻辑,将不同状态的行为局部化,避免Context中的复杂条件分支。

2、方便增加和删除状态,只需要改变状态类即可。

3、可以避免直接修改Context而引入不一致性。

4、提高了Context类的复用性。

缺点:

1、增加了类的数量,复杂度较高。

2、状态切换的条件分散在多个状态类中,不便维护。

3、状态类只能通过Context来间接访问资源,限制性较大。

应用场景

1、一个对象的行为依赖于它的状态,并且它必须在运行时刻根据状态改变它的行为。

2、代码中包含大量与状态有关的条件语句,这些条件语句的作用是根据对象的状态选择不同的行为,这样会导致代码混乱和不易维护。

3、一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。

4、需要管理的状态数量过多,这样就可以将不同的状态表示为不同的类。

5、系统中对象状态转换的规则比较复杂,状态模式可以将状态的转换逻辑集中到一个地方。

符合的设计原则:

1开闭原则(Open Closed Principle)

状态模式可以在不修改对象自身的情况下,在运行时动态切换状态,扩展新的状态类。符合开闭原则的要求,对扩展开放,对修改关闭。

2单一职责原则(Single Responsibility Principle)

每个状态类只负责对象在某一个状态下的行为。状态类之间互不影响,符合单一职责原则。

3里氏替换原则(Liskov Substitution Principle)

子类可以扩展父类状态的行为,而不会破坏父类状态的行为预期。符合里氏替换原则。

4依赖倒置原则(Dependency Inversion Principle)

状态类都依赖于抽象状态类,而不是具体的Context类。符合依赖倒置原则。

5接口隔离原则(Interface Segregation Principle)

抽象状态类提供简单的行为方法,避免客户端需要不必要的接口。符合接口隔离原则。

6组合聚合复用原则(Composite Reuse Principle)

客户端可以统一使用Context类,不需要与不同的具体状态类打交道。符合组合聚合复用原则。

7迪米特法则(Law of Demeter)

Context通过抽象状态类与各具体状态类交互,符合迪米特法则的“只与直接朋友通信”

总之,状态模式通过将复杂状态转换逻辑提取到不同的状态类中,可以提高代码的灵活性和可维护性,是一种比较常用和有效的设计模式。


http://www.ppmy.cn/news/870365.html

相关文章

INTEL芯片组驱动下载地址

https://downloadcenter.intel.com/download/29227/Chipset-INF-Utility

Arm居然为Cortex-M发布了专属显卡驱动!

(2D图形处理的技术其实早在红白机时代就成熟了,6502能做到的事情,Cortex-M自然也不在话下) 【说在前面的话】 在往期的文章《什么是嵌入式系统(下)——沉淀模型》我们曾提到过: 现在的计算机技术…

芯片驱动能力

驱动能力是后级电路带负载能力的大小,影响因素是后级负载大小、电压要求的大小等。对于要求精细的芯片来说,输出的电压和电流各不相同,但是总的功率是一定的。 74HC595(总线驱动器,典型的TTL型三态缓冲门电路&#xf…

AMD发布4.06.10.651版芯片组驱动 修复安装器无响应问题

AMD 刚刚为发布了 4.06.10.651 版芯片组驱动程序更新,主要添加了 USB4 官方支持、并为 Windows 11 操作系统带来新电源计划。与此同时,新版驱动也修复了之前可能在安装时弹出“AMD 芯片组软件无响应”的报错问题。 由变更日志可知,4.06.10.65…

Es存储和查询

基本概念 Cluster 集群,一个ES集群是由多个节点(Node)组成的,每个集群都有一个cluster name 作为标识, 在同一网段下的Es实例会通过cluster name 决定加入哪个集群下。 node 节点,一个ES实例就是一个node,一个机器可以…

【ThinkPHP】ThinkPHP中的门面(Facade)使用

门面为容器中的(动态)类提供了一个静态调用接口,相比于传统的静态方法调用, 带来了更好的可测试性和扩展性,可以为任何的非静态类库定义一个facade类。 系统已经为大部分核心类库定义了Facade,所以可以通过…

破解版xftp下载地址

http://down-www.newasp.net/pcdown/soft/dys/xftp6cn.rar