今天和你们聊『状态模式』这个设计模式,也是因为业务上遇到了一个极其难以维护的订单状态,不得不去重构。java
阿里规约其中就有一条:git
简单来讲,状态模式用于消除冗余的大量『if else』判断。程序员
业务中有一个订单表,其中订单状态大约有以下十多种,咱们维护在一个枚举类型中。github
接着,咱们有一个 service,用于流转状态用:面试
public interface OrderService {
/**
* 用户发起退款,流转当前订单到退款状态
* @param order
* @return
*/
boolean refund(Order order);
/**
* 用户取消订单
* @param order
* @return
*/
boolean cancle(Order order);
}
复制代码
而后他的实现类是这样:设计模式
@Service
public class OrderServiceImpl implements OrderService {
@Override
public boolean refund(Order order) {
boolean flag = true;
//判断当前订单状态
if (order.getOrderState() == OrderState.WAITSHIP.getCode() ||
order.getOrderState() == OrderState.PAYED.getCode()){
//若是是已付款、待发货,直接退款成功
order.setOrderState(OrderState.REFUND.getCode());
}else if (order.getOrderState() == OrderState.ALREADYSHIP.getCode() ||
order.getOrderState() == OrderState.ENDED.getCode()){
//若是是已发货了或交易完成了,流转到退款中,等待商家审核
order.setOrderState(OrderState.REFUNDING.getCode());
}else {
//其余状态都是异常状态,拒绝流转
flag = false;
}
return flag;
}
@Override
public boolean cancle(Order order) {
boolean flag = true;
//判断当前状态
if (order.getOrderState() == OrderState.NOTPAY.getCode()){
//只有未付款状态能够取消订单
order.setOrderState(OrderState.CANCELED.getCode());
}else {
flag = false;
}
return flag;
}
}
复制代码
一个简单的 refund 流转退款状态至少须要上面这么一大坨的 『if else』判断,下面的 cancle 取消订单状态的流转稍微简单些。微信
这里我也只精简了部分代码,实际上要复杂的更多,但好在状态之间的依赖性尚未太强,没有出现嵌套多层『if else』判断,状态模式怎么改?markdown
传统的判断模式之因此会有不少的『if else』判断,本质上就是不知道当前订单实什么状态,因此须要判断当前订单在不一样状态下该怎么流转。ide
第一步:建立一个抽象状态基类,在其中定义全部的状态流转操做,这里我只写了两个,实际业务中确定会有不少不少状态间的跳转。oop
@Slf4j
public abstract class AbstOrderState {
/**
* 用户发起退款,流转当前订单到退款状态
* @param order
* @return
*/
public boolean refund(Order order){
log.info("没法从状态:{} 流转到退款状态",getState());
return false;
}
/**
* 用户取消订单
* @param order
* @return
*/
public boolean cancle(Order order){
log.info("没法从状态:{} 流转到取消订单状态",getState());
return false;
}
/**
* 模板方法,获取当前状态
* @return
*/
public abstract String getState();
}
复制代码
第二步,为每一种状态建立对应的状态类,并集成抽象状态基类
第三步,分别实现各个状态下关心的流转操做,咱们举例其中两个状态子类的实现。
这个是已支付状态
public class PayEdState extends AbstOrderState {
@Override
public boolean refund(Order order){
//当前状态是已付款,目标状态是退款
order.setOrderState(OrderState.REFUND.getCode());
return true;
}
//当前状态是已付款,目标状态是取消订单状态,没法流转,异常的状态
//无需重写,使用抽象基类默认实现,返回失败便可
// @Override
// public boolean cancle(Order order){
// return false;
// }
@Override
public String getState(){
return OrderState.PAYED.getDesc();
}
}
复制代码
这个是未付款状态
public class NotPayState extends AbstOrderState {
@Override
public boolean refund(Order order){
//当前状态是未付款,目标状态是退款,直接成功
return true;
}
@Override
public boolean cancle(Order order){
//当前状态是未付款,目标状态是取消订单,直接成功
return true;
}
@Override
public String getState() {
return OrderState.NOTPAY.getDesc();
}
}
复制代码
第四步,如何使用
@Test
public void test(){
//初始化一个订单,默认未支付状态
Order order = new Order();
order.setOrderState(OrderState.NOTPAY.getCode());
//我想退款
AbstOrderState state = OrderState.getStateByCode(order.getOrderState());
if (state.refund(order)){
log.info("ok");
}else {
log.info("failed");
}
}
复制代码
至此,状态模式演示完毕,其实细心的你会发现,状态模式中未出现一行『if else』,但缺点就是多了不少类,但这是抽象性的必然结果。
实际订单状态这个例子并非很完美契合状态模式,由于状态之间依赖性没那么强,不多可能会出现嵌套判断,但效果是很显然的。
试想一下,若是之后个人订单增长了一个状态叫『冻结状态』,那么我只须要建立一个新的状态类,并只关心我这个冻结状态相关的流转操做,重写一下就行了,根本不用跑到以前的逻辑里改啊改。
状态模式仍是一个很是优秀的设计模式,推荐你们在项目里使用起来,除了初始编码的时候麻烦一点,后续的维护以及扩展真的近乎零成本。
近期会整理一个设计模式系列,分别讲讲 23 种设计模式,感兴趣的能够关注下哦~
关注公众不迷路,一个爱分享的程序员。 公众号回复「1024」加做者微信一块儿探讨学习! 公众号回复「面试题」送你一份面试题以及做者的做答答案 每篇文章用到的全部案例代码素材都会上传我我的 github github.com/SingleYam/o… 欢迎来踩!