美文网首页
设计模式实战:01.状态设计模式

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

作者: 城南码农 | 来源:发表于2019-03-21 19:50 被阅读0次

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

    需求背景

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

    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.状态设计模式

          本文链接:https://www.haomeiwen.com/subject/pgacvqtx.html