当前,我正在研究Order Microservice,其中有两种与订单状态更改store(Order order)
和updateStatus(int orderId, String status)
相关的方法,我将在后面解释。
订单有四种状态:
等待->已过期
等待->已取消
等待->购买
已购买->已取消
我已在下面提供了状态流程图,以使其清晰(希望如此)
创建订单时,状态将为“正在等待”,如果用户已付款,则状态将为“已购买”,如果买方或产品所有者取消了订单,则状态将为“已取消”,并且时间超过,则状态变为“已过期”。
对于每个我想工作的微服务,如果可能的话,我将实施四人行(Gang Of Four)设计模式,对于订单状态,我决定实施状态设计模式,因为它与之相关,并且在许多博客中都提到了这一点,例如文档状态内容(草稿,审阅等),音频播放器内容(已暂停,已播放等)等等。
这就是我所做的:
基本状态
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来使用状态模式。
然后,处理订单状态更改的正确方法是什么?
答案 0 :(得分:1)
实施状态设计模式的确切原因是最大程度地减少“开关内容/硬编码检查”,以及在不破坏当前代码的情况下灵活地添加更多状态(打开/关闭原理)
多态不能代替所有条件逻辑。
但是也许我错了,也许我缺乏知识,也许我太天真地决定使用这种模式。
考虑响应订单状态变化实际改变的行为。如果行为没有改变,则没有理由使用“状态”模式。
例如,如果订单的行为没有改变,则将整数(或枚举)或字符串分配为订单状态是可以的:
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()保持不变,则此代码可以正常工作。
但是,当doOperation()的行为由于状态变化而发生变化时,就会出现真正的问题。您最终将得到如下所示的方法:
...
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();
}
}
添加新状态非常容易,并且遵循“打开/关闭”主体。