状态模式
# 简单介绍
状态模式(State Pattern)是一种行为设计模式,它允许对象在其内部状态改变时改变其行为。状态模式的主要目的是将状态的转换逻辑和状态相关的操作封装在不同的类中,从而使得系统更易于扩展和维护
说白话就是在代码中合理的维护状态机的变更,这看上去很简单,不过也很重要,遇到适当的需求画出状态机变更图并且合理的实现它,是一个架构师的必经之路
主要组成部分:
1,Context(上下文):定义一个类,维护一个对当前所有涉及到的状态对象的引用,这东西很可能是聚合根 2,State(状态接口):定义一个接口,用于封装与状态相关的操作,也就是行为 3,ConcreteState(具体状态类):实现状态接口,每个具体状态类都包含与该状态相关的行为
# 一个例子
假设我们有一个简单的订单系统,订单有多种状态,如待支付、已支付、已确认、已取消、已发货、结束等。每种状态具有相似的行为,比如升单、自动关单、主动取消、支付、发货、确认收货等,但是每种状态对于每个行为的实现方式可能不同,行为所导致的流转后的状态也不一样
如果我们封装了下单、支付、发货接口,就会发现,订单类在待支付状态时,也是可以调用发货接口的,这显然不合理,用状态模式优化一下看看:
// 订单状态接口
interface OrderState {
void upgradeOrder(Order order); // 升单
void autoClose(Order order); // 自动关单
void cancel(Order order); // 主动取消
void pay(Order order); // 支付
void ship(Order order); // 发货
void confirmReceipt(Order order); // 确认收货
String getStateName(); // 获取状态名称
}
// 待支付状态
class PendingPaymentState implements OrderState {
@Override
public void upgradeOrder(Order order) {
System.out.println("待支付订单不能升单,请先支付");
}
@Override
public void autoClose(Order order) {
System.out.println("订单超时未支付,自动关闭");
order.setState(new CancelledState());
}
@Override
public void cancel(Order order) {
System.out.println("订单已取消");
order.setState(new CancelledState());
}
@Override
public void pay(Order order) {
System.out.println("支付成功");
order.setState(new PaidState());
}
@Override
public void ship(Order order) {
System.out.println("待支付订单不能发货");
}
@Override
public void confirmReceipt(Order order) {
System.out.println("待支付订单不能确认收货");
}
@Override
public String getStateName() {
return "待支付";
}
}
// 已支付状态
class PaidState implements OrderState {
@Override
public void upgradeOrder(Order order) {
System.out.println("订单已升级为VIP订单");
// 升级逻辑...
}
@Override
public void autoClose(Order order) {
System.out.println("已支付订单不会自动关闭");
}
@Override
public void cancel(Order order) {
System.out.println("已支付订单取消,需要退款处理");
order.setState(new CancelledState());
}
@Override
public void pay(Order order) {
System.out.println("订单已支付,无需重复支付");
}
@Override
public void ship(Order order) {
System.out.println("订单已发货");
order.setState(new ShippedState());
}
@Override
public void confirmReceipt(Order order) {
System.out.println("订单尚未发货,不能确认收货");
}
@Override
public String getStateName() {
return "已支付";
}
}
// 上下文:订单类,订单类中包含了订单状态,每次需要修改状态时,需要取出当前状态,然后调用该状态的某个行为方法
class Order {
private OrderState currentState;
public Order() {
this.currentState = new PendingState();
}
public void setState(OrderState state) {
this.currentState = state;
}
public void confirm() {
currentState.confirm(this);
}
// 其他委托方法...
}
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
# 一些思考
它为我们的编程提供了一些合理的指导思想。比如我们很多时候会遇到类似这样的问题:一个大订单下面有很多小订单,我们在修改大文档状态的时候也需要修改该文档下评论状态、推荐文章的状态等,我们需要在业务中维持各个状态的一致性,同时状态的流转非常多,比如订单可以直接关单,也可以等用户支付,用户支付后直接关单,这时候两种关单行为是不一样的
借鉴状态模式,我们可以先将状态机变更的流程图画出来, 比如:
每一个状态变更操作抽象出一个方法,这些方法可以放在聚合根或者聚合中,调用这些方法的时候统一变更这些状态,这样这些状态就变得易于维护了。当然上面的例子比较简单,多个状态只有一个取消的逻辑相似,但是当需求中多个状态有多个行为逻辑相似时,状态模式的优点就展示出来了