16-状态模式

状态模式

分析

H2O的三种状态(未考虑临界点)

image-20230211143306040

1、在软件系统中:

  • 有些对象具有多种状态

  • 这些状态在某些情况下能够相互转换

  • 对象在不同的状态下将具有不同的行为

2、复杂的条件判断语句来进行状态的判断和转换操作 \longrightarrow 导致代码的可维护性和灵活性下降 \longrightarrow 出现新的状态时,代码的扩展性很差,客户端代码也需要进行相应的修改,违背了开闭原则

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TestXYZ {
int behaviour;
//省略Getter和Setter方法
......
public void handleAll() {
if (behaviour == 0) {
//do something }
else if (behaviour == 1) {
//do something }
else if (behaviour == 2) {
//do something }
else if (behaviour == 3) {
//do something }
... some more else if ...
}
}

状态模式的定义

image-20230211143719363

对象行为型模式

  • 又名状态对象(Objects for States)

  • 用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题

  • 将一个对象的状态从该对象中分离出来封装到专门的状态类中,使得对象状态可以灵活变化

  • 对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理

状态模式结构

image-20230211143932735

状态模式包含以下3个角色:
  • Context(环境类)

  • State(抽象状态类)

  • ConcreteState(具体状态类)

典型的抽象状态类代码
1
2
3
4
public abstract class State {
//声明抽象业务方法,不同的具体状态类可以有不同的实现
public abstract void handle();
}
典型的具体状态类代码
1
2
3
4
5
public class ConcreteState extends State {
public void handle() {
//方法具体实现代码
}
}
典型的环境类代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Context {
private State state; //维持一个对抽象状态对象的引用
private int value; //其他属性值,该属性值的变化可能会导致对象的状态发生变化

public void setState(State state) {
this.state = state;
}

public void request() {
//其他代码
state.handle(); //调用状态对象的业务方法
//其他代码
}
}
状态模式实现

(1) 统一由环境类来负责状态之间的转换,环境类充当了状态管理器(State Manager)角色

1
2
3
4
5
6
7
8
9
10
11
12
……
public void changeState() {
//判断属性值,根据属性值进行状态转换
if (value == 0) {
this.setState(new ConcreteStateA());
}
else if (value == 1) {
this.setState(new ConcreteStateB());
}
......
}
……

(2) 由具体状态类来负责状态之间的转换,可以在具体状态类的业务方法中判断环境类的某些属性值,再根据情况为环境类设置新的状态对象,实现状态转换

1
2
3
4
5
6
7
8
9
10
11
12
……
public void changeState(Context ctx) {
//根据环境对象中的属性值进行状态转换
if (ctx.getValue() == 1) {
ctx.setState(new ConcreteStateB());
}
else if (ctx.getValue() == 2) {
ctx.setState(new ConcreteStateC());
}
......
}
……
实例类图

image-20230211144351815

image-20230211144424371

image-20230211144430035

(1) Account:银行账户,充当环境类

(2) AccountState:账户状态类,充当抽象状态类

(3) NormalState:正常状态类,充当具体状态类

(4) OverdraftState:透支状态类,充当具体状态类

(5) RestrictedState:受限状态类,充当具体状态类

(6) Client:客户端测试类

结果及分析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
段誉开户,初始金额为0.0
---------------------------------------------
段誉存款1000.0
现在余额为1000.0
现在帐户状态为designpatterns.state.NormalState
---------------------------------------------
段誉取款2000.0
现在余额为-1000.0
现在帐户状态为designpatterns.state.OverdraftState
---------------------------------------------
段誉存款3000.0
现在余额为2000.0
现在帐户状态为designpatterns.state.NormalState
---------------------------------------------
段誉取款4000.0
现在余额为-2000.0
现在帐户状态为designpatterns.state.RestrictedState
---------------------------------------------
段誉取款1000.0
帐号受限,取款失败
现在余额为-2000.0
现在帐户状态为designpatterns.state.RestrictedState
---------------------------------------------
计算利息!

共享状态

动机
  • 在有些情况下,多个环境对象可能需要共享同一个状态

  • 如果希望在系统中实现多个环境对象共享一个或多个状态对象,那么需要将这些状态对象定义为环境类的静态成员对象

开关的状态设计结构图

image-20230211144705592

  • 开关类:Switch(环境类)

  • 开关状态类:SwitchState (抽象状态类)

  • 打开状态类:OnState(具体状态类)

  • 关闭状态类:OffState (具体状态类)

  • 客户端测试类:Client

使用环境类实现状态转换

动机
  • 对于客户端而言,无须关心状态类,可以为环境类设置默认的状态类,将状态的转换工作交给环境类(或具体状态类)来完成,具体的转换细节对于客户端而言是透明的

  • 可以通过环境类来实现状态转换,环境类作为一个状态管理器,统一实现各种状态之间的转换操作

实例类图

image-20230211145010503

image-20230211145016630

  • 屏幕类:Screen (环境类)

  • 抽象状态类:State

  • 正常状态类:NormalState (具体状态类)

  • 二倍状态类:LargerState (具体状态类)

  • 四倍状态类:LargestState (具体状态类)

  • 客户端测试类:Client

模式优点

  • 封装了状态的转换规则,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中

  • 将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为

  • 允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块,可以避免使用庞大的条件语句来将业务方法和状态转换代码交织在一起

  • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数

模式缺点

  • 会增加系统中类和对象的个数,导致系统运行开销增大

  • 结构与实现都较为复杂,如果使用不当将导致程序结构和代码混乱,增加系统设计的难度

  • 对开闭原则的支持并不太好增加新的状态类需要修改负责状态转换的源代码,否则无法转换到新增状态;而且修改某个状态类的行为也需要修改对应类的源代码

模式适用环境

  • 对象的行为依赖于它的状态(例如某些属性值),状态的改变将导致行为的变化

  • 在代码中包含大量与对象状态有关的条件语句这些条件语句的出现会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2023-2024 Guijie Wang
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信