oop - 如何使用状态设计模式处理订单状态更改
问题描述
目前,我正在做订单微服务,其中有两种与订单状态更改相关的方法store(Order order)
,updateStatus(int orderId, String status)
我稍后会解释。
该命令有四种状态:
等待 -> 已过期
等待 -> 取消
等待 -> 购买
已购买 -> 已取消
我在下面提供了状态流程图,以使其清楚(希望如此)
订单创建时状态为“Waiting”,如果用户已付款则状态为“Purchased”,如果买家或产品负责人取消则状态为“Canceled”,如果超过时间则状态变为“已过期”。
对于我想要处理的每一个微服务,如果可能的话,我将实施四人组设计模式,对于订单状态,我决定实施状态设计模式,因为它是相关的,并且来自我在许多博客中提到的内容,比如在文档状态的东西(草稿、审查中等)、音频播放器的东西(暂停、播放等)等等。
这就是我所做的:
基础状态
public interface OrderStatus {
void updateStatus(OrderContext orderContext);
}
等待状态
public class WaitingState implements OrderStatus {
// omited for brevity
@Override
public void updateStatus(OrderContext orderContext) {
orderContext.getOrder().setStatus("Waiting");
}
}
购买状态
public class PurchasedState implements OrderStatus {
// omited for brevity
@Override
public void updateStatus(OrderContext orderContext) {
orderContext.getOrder().setStatus("Purchased");
}
}
其他州
..
语境:
public class OrderContext {
private OrderStatus currentStatus;
private Order order;
public OrderContext(OrderStatus currentStatus, Order order) {
this.currentStatus = currentStatus;
this.order = order;
}
public void updateState() {
currentStatus.updateStatus(this);
}
public OrderStatus getCurrentStatus() {
return currentStatus;
}
public void setCurrentStatus(OrderStatus currentStatus) {
this.currentStatus = currentStatus;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
客户端是我从 OrderController 调用的 OrderServiceImpl。
public class OrderServiceImpl implements OrderService {
// omited for brevity
@Override
public Order store(Order order) {
WaitingState state = WaitingState.getInstance();
OrderContext context = new OrderContext(state, order);
context.updateState();
// do other stuff
}
@Override
public void updateStatus(int orderId, String status) {
Order order = orderRepository.findById(id);
// but how about this?? this still requires me to use if/else or switch
}
}
如您所见,我可以在store(Order order)
方法中创建 Order 时执行此操作,但我不知道要执行此操作,updateStatus(int orderId, String status)
因为仍然需要检查状态值才能使用正确的状态。
switch (status) {
case "EXPIRED": {
ExpiredState state = ExpiredState.getInstance();
OrderContext context = new OrderContext(state, order);
context.updateState();
// do something
break;
}
case "CANCELED": {
CanceledState state = CanceledState.getInstance();
OrderContext context = new OrderContext(state, order);
context.updateState();
// do something
break;
}
// other case
default:
// do something
break;
}
实现状态设计模式的确切原因是最大限度地减少“开关内容/硬编码检查”以及在不破坏当前代码的情况下添加更多状态的灵活性(打开/关闭原则),但也许我错了,也许我缺乏知识,也许我太天真决定使用这种模式。但最终,我发现我仍然需要使用 switch 的东西来使用状态模式。
那么,处理订单状态变化的正确方法是什么?
解决方案
实现状态设计模式的确切原因是最大限度地减少“开关材料/硬编码检查”以及在不破坏当前代码的情况下添加更多状态的灵活性(打开/关闭原则)
多态并不能取代所有的条件逻辑。
但也许我错了,也许我缺乏知识,也许我太天真而无法决定使用这种模式。
考虑响应订单状态变化的实际行为变化。如果没有行为改变,就没有理由使用状态模式。
例如,如果订单的行为没有改变,分配一个整数(或枚举)或字符串作为订单状态就可以了:
enum OrderStatus {
WAITING,
CANCELLED,
EXPIRED,
PURCHASED
}
class Order {
private OrderStatus status;
public Order() {
status = OrderStatus.WAITING;
}
public void setStatus(OrderStatus s) {
status = s;
}
public void doOperation1() {
System.out.println("order status does not affect this method's behavior");
}
public void doOperation2() {
System.out.println("order status does not affect this method's behavior");
}
public void doOperation3() {
System.out.println("order status does not affect this method's behavior");
}
}
如果尽管状态发生变化,doOperation()s 保持不变,则此代码可以正常工作。
但是,当 doOperation()s 的行为由于状态变化而发生变化时,就会出现真正的问题。您最终会得到如下所示的方法:
...
public void doOperation3() {
switch (status) {
case OrderStatus.WAITING:
// waiting behavior
break;
case OrderStatus.CANCELLED:
// cancelled behavior
break;
case OrderStatus.PURCHASED:
// etc
break;
}
}
...
对于许多操作,这是不可维护的。添加更多 OrderStatus 将变得复杂并影响许多 Order 操作,违反 Open/Closed Principal。
状态模式旨在专门解决这个问题。一旦您确定了哪些行为发生了变化,您就可以将它们提取到一个界面中。让我们想象一下 doOperation1() 的变化:
interface OrderStatus {
void doOperation1();
}
class WaitingOrderStatus implements OrderStatus {
public void doOperation1() {
System.out.println("waiting: doOperation1()");
}
public String toString() {
return "WAITING";
}
}
class CancelledOrderStatus implements OrderStatus {
public void doOperation1() {
System.out.println("cancelled: doOperation1()");
}
public String toString() {
return "CANCELLED";
}
}
class Order implements OrderStatus {
private OrderStatus status;
public Order() {
status = new WaitingOrderStatus();
}
public void setStatus(OrderStatus s) {
status = s;
}
public void doOperation1() {
status.doOperation1();
}
public void doOperation2() {
System.out.println("order status does not affect this method's behavior");
}
public void doOperation3() {
System.out.println("order status does not affect this method's behavior");
}
}
class Code {
public static void main(String[ ] args) {
Order o = new Order();
o.doOperation1();
}
}
添加新状态很容易,而且它遵循 Open/Closed Principal。
推荐阅读
- vue.js - NuxtJS - 无法读取未定义的属性“标题” - 奇怪的行为
- c# - 损坏的符号链接文件引发 FileNotFoundException 但通过 File.Exists
- excel - 如何根据单元格值调用命令按钮单击事件?
- java - 登录错误:java.sql.SQLException:找不到列'user.id'
- angular - PouchDB 更改仅在第二次单击后触发
- android - 如何显示文本视图/布局来代替空的回收视图?
- python - 当我运行我的代码应该让玩家看着鼠标时,他会发疯
- jquery - 当我选择第一个列表值时,ajax 动态下拉菜单不起作用
- flutter - 如何仅突出显示 GridView.build 上的 onTaped 项?
- c - C: 从 char* 创建数组