设计模式之状态模式

状态模式

状态模式

状态模式( State Pattern)也称为状态机模式( State Machine Pattern),是允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类,属于行为型模式。

状态模式中类的行为是由状态決定的,不同的状态下有不同的行为。其意图是让一个对象在其内部改变的时候,其行为也随之改变。状态模式核心是状态与行为绑定,不同的状态对应不同的行为。

通用UML类图如下

image-20210426233005887

从UML类图中,我们可以看到,状态模式主要包含三种角色

1、环境类角色(Context):定义客户端需要的接口,内部维护一个当前状态实例,并负责具体状态的切换;

2、抽象状态角色(State):定义该状态下的行为,可以有一个或多个行为;

3、具体状态角色(ConcreteState):具体实现该状态对应的行为,并且在需要的情况下进行状态切换。

状态模式的应用场景

在软件开发过程中,对于某一项操作,可能存在不同的情況。

通常处理多情况问题最直接的方式就是使用if..else或 switch..case条件语句进行枚举。

但是这种做法对于复杂状态的判断天然存在弊端:条件判断语句过于臃肿,可读性差,且不具备扩展性,维抑难度也大。而如果转换思维,将这些不同状态独立起来用各个不同的类进行表示,系统处于哪种情况,直接使用相应的状态类对象进行处理,消除了if. else, switch..case等冗余语句,代码更有层次性且具备良好扩展力。

状态模式主要解決的就是当控制一个对象状态的条件表达式过于复杂时的情況。通过把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。对象的行为依赖于它的状态(属性),并且会根据它的状态改变而改变它的相关行为。

状态模式适用于以下场景

1、行为随状态改变而改变的场景;

2、操作中含有庞大的多分支结构,并且这些分支取决于对象的状态。

通用代码

抽象状态角色(State)

1
2
3
4
public interface IState
{
IState handle();
}

具体状态角色(ConcreteState)

ConcreteStateA

1
2
3
4
5
6
7
8
9
public class ConcreteStateA implements IState
{
@Override
public IState handle()
{
System.out.println("ConcreteStateA");
return new ConcreteStateB();
}
}

ConcreteStateB

1
2
3
4
5
6
7
8
9
public class ConcreteStateB implements IState
{
@Override
public IState handle()
{
System.out.println("ConcreteStateB");
return new ConcreteStateA();
}
}

环境类角色(Context)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Context
{
private IState state;

public Context()
{
setState(new ConcreteStateA());
}

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

public void handle()
{
setState(state.handle());
}

public void transferToA()
{
setState(new ConcreteStateA());
}

public void transferToB()
{
setState(new ConcreteStateB());
}
}

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main
{
public static void main(String[] args)
{
Context context = new Context();
context.handle();
context.handle();
context.transferToB();
context.handle();
context.transferToA();
context.handle();
}
}

输出

1
2
3
4
ConcreteStateA
ConcreteStateB
ConcreteStateB
ConcreteStateA

状态模式相关的设计模式

1、状态模式与责任链模式

状态模式和责任链模式都能消除if分支过多的问题。但某些情況下,状态模式中的状态可以理解为责任,那么这种情况下,两种模式都可以使用,从定义来看,状态模式强调的是一个对象内在状态的改变,而责任链模式强调的是外部节点对象间的改变。

从其代码实现上来看,他们间最大的区别就是状态模式各个状态对象知道自己下ー个要进入的状态对象;而责任链模式并不清楚其下ー个节点处理对象,因为链式组装由客户端负责。

2、状态模式与策略模式

状态模式和策略模式的UML类图架构有些类似,但他们的应用场景是不一样的,策略模式多种算法行为择其一都能满足,彼此之间是独立的,用户可自行更换策略算法;而状态模式各个状态间是存在相互关系的,彼此之间在一定条件下存在自动切换状态效果,且用户无法指定状态,只能设置初始状态。

状态模式的优缺点

优点

1、结构清晰:将状态独立为类,消除了元余的if.else或 switch..case语句,使代码更加简洁提高系统可维护性

2、将状态转换显示化:通常的对象内部都是使用数值类型来定义状态,状态的切换是通过赋值进行表现,不够直观;而使用状态类,在切换状态时,是以不同的类进行表示,转换目的更加明确;

3、状态类职责明确且具备扩展性。

缺点

1、类膨胀:如果一个事物具备很多状态,则会造成状态类太多

2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱

3、状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新増状态,而且修改某个状态类的行为也需修改对应类的源代码。

打赏

请我喝杯咖啡吧~

支付宝
微信