如何使用状态设计模式处理订单状态变化
How to handle Order status changes with State Design Pattern
目前,我正在做订单微服务,其中我有两个与订单状态变化相关的方法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)
方法中创建订单时执行此操作,但我不知道在 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;
}
实现状态设计模式的确切原因是最小化“开关 stuff/hardcoded 检查”和在不破坏当前代码的情况下添加更多状态的灵活性(Open/Close 原则),但也许我错了,也许我知识匮乏,也许我太天真而没有决定使用这种模式。
但是到了最后,我发现我仍然需要使用开关的东西来使用状态模式。
那么,如何处理订单状态变化才是正确的呢?
The exact reason to implement the state design pattern is to minimize "the switch stuff/hardcoded checking" and the flexibility for adding more state without breaking current code (Open/Close principle)
多态性不会取代所有条件逻辑。
but maybe I'm wrong, maybe I'm lack of knowledge, maybe I'm too naive to decide to use this pattern.
考虑响应订单状态变化实际会发生哪些行为变化。如果行为没有改变,就没有理由使用状态模式。
例如,如果订单的行为没有改变,分配一个整数(或枚举)或字符串作为订单状态就可以了:
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() 的行为因状态变化而改变时,真正的问题开始出现。您最终会得到如下所示的方法:
...
public void doOperation3() {
switch (status) {
case OrderStatus.WAITING:
// waiting behavior
break;
case OrderStatus.CANCELLED:
// cancelled behavior
break;
case OrderStatus.PURCHASED:
// etc
break;
}
}
...
对于许多操作来说,这是不可维护的。添加更多 OrderStatus 将变得复杂并影响许多订单操作,违反了 Open/Closed 原则。
状态模式就是专门用来解决这个问题的。一旦你确定了哪些行为发生了变化,你就可以将它们提取到一个界面中。假设 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 原则。
目前,我正在做订单微服务,其中我有两个与订单状态变化相关的方法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)
方法中创建订单时执行此操作,但我不知道在 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;
}
实现状态设计模式的确切原因是最小化“开关 stuff/hardcoded 检查”和在不破坏当前代码的情况下添加更多状态的灵活性(Open/Close 原则),但也许我错了,也许我知识匮乏,也许我太天真而没有决定使用这种模式。 但是到了最后,我发现我仍然需要使用开关的东西来使用状态模式。
那么,如何处理订单状态变化才是正确的呢?
The exact reason to implement the state design pattern is to minimize "the switch stuff/hardcoded checking" and the flexibility for adding more state without breaking current code (Open/Close principle)
多态性不会取代所有条件逻辑。
but maybe I'm wrong, maybe I'm lack of knowledge, maybe I'm too naive to decide to use this pattern.
考虑响应订单状态变化实际会发生哪些行为变化。如果行为没有改变,就没有理由使用状态模式。
例如,如果订单的行为没有改变,分配一个整数(或枚举)或字符串作为订单状态就可以了:
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() 的行为因状态变化而改变时,真正的问题开始出现。您最终会得到如下所示的方法:
...
public void doOperation3() {
switch (status) {
case OrderStatus.WAITING:
// waiting behavior
break;
case OrderStatus.CANCELLED:
// cancelled behavior
break;
case OrderStatus.PURCHASED:
// etc
break;
}
}
...
对于许多操作来说,这是不可维护的。添加更多 OrderStatus 将变得复杂并影响许多订单操作,违反了 Open/Closed 原则。
状态模式就是专门用来解决这个问题的。一旦你确定了哪些行为发生了变化,你就可以将它们提取到一个界面中。假设 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 原则。