设计模式实战:01.状态设计模式

本系列文章不关注设计模式的理论,侧重于怎么把设计模式用在实际的业务场景中。

需求背景

最近接到一个业务需求,大概业务流程是这样:

user state

分析下这个需求:

  • 分别代表5中用户状态,UnActiveState,normalSate,freezeState,deleteSate..
  • 根据业务规则,5中状态之间可以相互转换。(箭头所示)
  • 状态不能转换到自己。
    最常规的编码方式:
// 伪代码
boolean result =false
private UserState cur;
private UserState target;
if((cur=UnActiveState & target=normalSate)||(cur=UnActiveState & target=deleteSate)){
  result =true;
}else if((cur=normalSate& target=freezeState)||(cur=normalSate& target=deleteSate)){
  result =true;
}
.....

上述的代码存在几个问题。非常难以维护的,而且完全没什么逻辑可言,每个状态之间耦合非常严重。另外,阿里巴巴java规范也告诉每个程序员,要少写复杂的if逻辑判断。否则就应该检查开发自己的逻辑思维。
接下来,我们用转台模式来实现这个业务功能:

用状态模式实现

定义每一个状态类

定义用户状态的基类,把所有状态允许的切换操作(箭头流向)定义为方法。(eg.未激活 - 正常 定义为active())

/**
 * @description: 抽象所有用户状态操作,默认都不允许。让子类去复写
 * @author: DENGHUANQING1
 * @create: 2019-03-08 19:16
 **/
public class UserState {
    /**
     * 激活
     *
     * @param user
     * @return
     */
    public Integer active(SysUserEntity user){
        throw new BusinessException("用户状态不允许此操作");
    };

    /**
     * 冻结
     *
     * @param user
     * @return
     */
    public Integer freeze(SysUserEntity user){
        throw new BusinessException("用户状态不允许此操作");
    };

    /**
     * 解冻
     * @param user
     * @return
     */
    public Integer unfreeze(SysUserEntity user){
        throw new BusinessException("用户状态不允许此操作");
    };


    /**
     * 申诉成功
     * @param user
     * @return
     */
    public Integer applySuc(SysUserEntity user){
        throw new BusinessException("用户状态不允许此操作");
    };

    /**
     * 删除:默认状态都允许删除
     * @param user
     * @return
     */
    public Integer delete(SysUserEntity user){
        return UserStatusEnum.DELETE.getValue();
    };
}

把用户的每一个状态定义为单独的状态类,每个状态类继承UserState。实现可以操作的方法,即允许的数据流向。
未激活状态,只允许激活操作和删除操作:

/**
 * @description:
 * @author: DENGHUANQING1
 * @create: 2019-03-09 21:06
 **/
public class UnActiveState extends UserState {
    @Override
    public Integer active(SysUserEntity user) {
        return UserStatusEnum.ACTIVED.getValue();
    }
}

正常状态只允许冻结操作和删除操作:

/**
 * @description:
 * @author: DENGHUANQING1
 * @create: 2019-03-09 21:07
 **/
public class NormalSate extends UserState {
    @Override
    public Integer freeze(SysUserEntity user) {
        return UserStatusEnum.FROZEN.getValue();
    }
}

.......
定义完所有的状态后,对于单独的状态,程序只用关注此状态能做什么操作。这里由于每个状态能实现的操作远远小于所有的操作。所以UserState并没有定义为抽象类。大家可以根据自己需求定制。UserState类对默认无法通过的操作抛出的自定义的业务异常。

抽象用户的请求

接受前端的用户请求,需要做两件事情。

  • 判断当前用户的状态
  • 判断用户即将切换的状态是属于上面定义的那种操作(UserState的方法)
public class UserServiceImpl implements UserService {
    @Override
    public Integer switchState(SysUserEntity user, int state) {
        if (user.getState() == state) {
            // 用户状态不需要修改
            return user.getState();
        }
      //判断当前用户的状态
        UserState userState = UserStateContext.getUserSate(user);
        MixcAsserts.isNotNull(userState, "用户状态不允许此操作");

    // 判断用户的操作并且执行操作【1】
        if (user.getState() == 0 && state == 1) {
            // 激活用户
            return userState.active(user);
        } else if (user.getState() == 1 && state == 2) {
            return userState.freeze(user);
        } else if (user.getState() == 2 && state == 1) {
            return userState.unfreeze(user);
        } else if (user.getState() != 4 && state == 4) {
            return userState.delete(user);
        } else {
            throw new BusinessException("用户状态不允许此操作");
        }
    }
}

静态工厂获取当前用户状态:

public class UserStateContext {
    private static UserState unActiveState;
    private static UserState normalSate;
    private static UserState freezeState;

    static {
        unActiveState = new UnActiveState();
        normalSate = new NormalSate();
        freezeState = new FreezeState();
    }

    public static UserState getUserSate(SysUserEntity entity) {
        switch (entity.getState()) {
            case 0:
                return unActiveState;
            case 1:
                return normalSate;
            case 2:
                return freezeState;
        }
        return null;
    }
}

总结

整体通过状态模式改造下来,我们的代码逻辑看起来清爽了很多,对于维护的同学来说也许会更明确一点。在【1】处其实也是做了很多的判断,目前没有想到比较优雅的实现方式。欢迎大家指点。

你可能感兴趣的:(设计模式实战:01.状态设计模式)