设计模式20-State

本文最后更新于:3 years ago

状态模式

  在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于 行为型模式

在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。

如果想了解状态模式的具体的介绍,菜鸟教程介绍得比较详细↓
菜鸟教程-状态模式

结构图


优缺点

优点:

1、封装了转换规则。
2、枚举可能的状态,在枚举状态之前需要确定状态种类。
3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点:

1、状态模式的使用必然会增加系统类和对象的个数。
2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
3、状态模式对”开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

使用场景

1、行为随状态改变而改变的场景。
2、条件、分支语句的代替者。

实现代码

首先提出需求,我们模拟将汽车在不同状态时,所能执行的操作也是不一样的
什么意思呢?当汽车在驾驶状态时,我们是不能够开车门和关车门的,但是可以进行驾驶和停下操作
而当汽车在关闭状态下,我们是可以开车门,关车门,但是不能够执行驾驶和停下的操作

需求很简单,正常实现,代码如下:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class Main{
public static void main(String[] args) {
Car car = new Car();
CarState state = new CarState();
state.state = "Running";
car.setState(state);
car.runTheCar();
car.stopTheCar();
car.openTheDoor();
car.closeTheDoor();
}
}

class Car {

CarState carState;

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

public void openTheDoor() {
if (carState.state.equals("Running")) {
System.out.println("Car is Running!Can't open the door");
}
if (carState.equals("Closed")) {
System.out.println("Car is Closed!Can open the door");
}
}

public void closeTheDoor() {
if (carState.state.equals("Running")) {
System.out.println("Car is Running!Can't close the door");
}
if (carState.state.equals("Closed")){
System.out.println("Car is Closed!Can close the door");
}
}

public void runTheCar() {
if (carState.state.equals("Running")) {
System.out.println("Car is Running!Can run the door");
}
if (carState.state.equals("Closed")) {
System.out.println("Car is Closed!Can't run the car");
}
}

public void stopTheCar() {
if (carState.state.equals("Running")) {
System.out.println("Car is Running!Can stop the door");
}
if (carState.state.equals("Closed")) {
System.out.println("Car is Closed!Can't stop the car");
}
}
}

class CarState{
String state;
}

结果如下:

1
2
3
4
Car is Running!Can run the door
Car is Running!Can stop the door
Car is Running!Can't open the door
Car is Running!Can't close the door

我们在Car中对每个方法进行了比较,如果是驾驶状态/停下状态,不同的操作有着不同的结果
代码很简单,但是细想一下,此时当我们添加新的状态时,是不是很不方遍,你需要在每一个方法中都需要去添加相应的反应,
这个时候就需要用到状态模式了

当一个类中的动作根据它的状态的不同会有不同的反应,这个时候就可以应用State模式
如果一个类它的很多operation,都是需要根据不同的State来实现,那么我们就可以把State抽象出来,在State中实现这些方法

还是刚刚那个需求,我们用State模式,重构一下代码

代码如下:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
public class Main {
public static void main(String[] args) {
Car car = new Car();

CarState carCloseState = new CarClosedState();
car.setState(carCloseState);
car.closeTheDoor();
car.runTheCar();
car.openTheDoor();
car.stopTheCar();
}
}

public class Car {
private CarState state;

public Car() {
this.state = null;
}

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

public void openTheDoor() {
state.openTheDoor();
}

public void closeTheDoor() {
state.closeTheDoor();
}

public void runTheCar() {
state.runTheCar();
}

public void stopTheCar() {
state.stopTheCar();
}
}

public abstract class CarState {
abstract void openTheDoor();
abstract void closeTheDoor();
abstract void runTheCar();
abstract void stopTheCar();
}

public class CarOpenState extends CarState{
@Override
void openTheDoor() {
System.out.println("Car is Open!Can open the door");
}

@Override
void closeTheDoor() {
System.out.println("Car is Open!Can close the door");
}

@Override
void runTheCar() {
System.out.println("Car is Open!Can run thr car");
}

@Override
void stopTheCar() {
System.out.println("Car is Open!Can't stop the door");
}
}

public class CarClosedState extends CarState {
@Override
void openTheDoor() {
System.out.println("Car is Closed!Can open the door");
}

@Override
void closeTheDoor() {
System.out.println("Car is Closed!Can close the door");
}

@Override
void runTheCar() {
System.out.println("Car is Closed!Can't run the car");
}

@Override
void stopTheCar() {
System.out.println("Car is Closed!Can't stop the car");
}
}

public class CarRunningState extends CarState{
@Override
void openTheDoor() {
System.out.println("Car is Running!Can't open the door");
}

@Override
void closeTheDoor() {
System.out.println("Car is Running!Can't close the door");
}

@Override
void runTheCar() {
System.out.println("Car is Running!Can run the door");
}

@Override
void stopTheCar() {
System.out.println("Car is Running!Can stop the door");
}
}

public class CarStoppedState extends CarState{
@Override
void openTheDoor() {
System.out.println("Car is Stop!Can open the door");
}

@Override
void closeTheDoor() {
System.out.println("Car is Stop!Can close the door");
}

@Override
void runTheCar() {
System.out.println("Car is Stop!Can run the door");
}

@Override
void stopTheCar() {
System.out.println("Car is Stop!Can stop the door");
}
}

结果如下:

1
2
3
4
Car is Closed!Can close the door
Car is Closed!Can't run the car
Car is Closed!Can open the door
Car is Closed!Can't stop the car

你可以试着先自己去理解这段代码

我们先创建一个接口CarState,其中的有四个方法,我们将模拟不同状态下的不同操作开门、关门、开车、停车
接着,我们模拟了汽车的四种状态:CarOpenState、CarClosedState、CarRunnning、CarStopping,并且都继承CarState,重写方法
最后我们创建Car,在Car中我们创建CarState来表示Car的状态
在Main中我们将创建的具体状态传入实例化的car,调用相应的方法,栗子还是很容易理解的

对于State模式来讲,如果你想要扩展自己(CarState)的方法,就不建议采用State模式了(当你扩展operation时,State模式中所有operation都需要扩展)
如果并不需要对State的类型进行扩展,也不建议采用State模式(会导致子类很多)
当你的operation不会进行扩展时,可以采用State模式

在学习State模式的时候,有看到一篇写的很好的关于State模式的文章这里可以去看看,写的很用心,不像我水一水文章👇

设计模式:状态(State)模式


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!