美文网首页技术干货
设计模式-状态模式

设计模式-状态模式

作者: KevinLive | 来源:发表于2017-04-28 16:24 被阅读22次

    Tip:

    • 该图为UML图
    • 类包含3个组成部分,第一栏为类名,第二栏为属性,第三栏为方法
    • 属性和方法前可加一个可见性修饰符, + 号表示 public 修饰符, - 号表示 private 修饰符, # 号表示 protected 修饰符,省略表示包级可见。
    • 接口包含2个组成部分,第一栏为接口名,第二栏为方法,在接口名之上加上 <<interface>>

    使用场景

    比如游戏中一个用户的用过外挂违规次数属性,如果用户用过1~3次,每次警告制裁;3次以上,每次封号3天;5次以上,每次封号1周;到达10次,永久封号。

    根据以上描述可以分为四种状态:

    • 警告
    • 封号3天
    • 封号1周
    • 永久封号

    源码

    环境角色

    public class PunishManager {
    
        //保存违规用户及次数
        private Map<String, Integer> mPunishMap = new HashMap<>();
    
    
        /**
         * 获取违规用户及次数
         */
        Map<String, Integer> getPunishMap() {
            return mPunishMap;
        }
    
        /**
         * 获取具体状态角色,封装转换规则
         *
         * @param oldPunishCount 违规次数
         * @return 具体状态角色
         */
        private PunishState getPunishState(Integer oldPunishCount) {
    
            //推荐尽量少用else,如果超过3层if-else代码推荐使用卫语句
            if (oldPunishCount <= 3) {
                return new LowPunishState();
            }
    
            if (oldPunishCount <= 5) {
                return new MidPunishState();
            }
    
            if (oldPunishCount < 10) {
                return new HeightPunishState();
            }
    
            return new BlackPunishState();
        }
    
        /**
         * 违规处理
         *
         * @param uid 用户ID
         */
        public void punish(String uid) {
            //获取之前违规次数
            Integer oldPunishCount = mPunishMap.get(uid);
    
            if (oldPunishCount == null) {
                oldPunishCount = 0;
            }
    
            oldPunishCount += 1;
            mPunishMap.put(uid, oldPunishCount);
    
            //获取对应状态对象进行响应操作
            getPunishState(oldPunishCount).punish(uid, oldPunishCount, this);
        }
    }
    

    抽象状态角色

    public interface PunishState {
        /**
         * 违规处理
         *
         * @param uid            用户ID
         * @param violationCount 违规次数
         * @param punishManager  环境角色
         */
        public void punish(String uid, int violationCount, PunishManager punishManager);
    }
    

    具体状态角色

    根据不同的具体状态角色做相应的业务

    public class LowPunishState implements PunishState {
    
        @Override
        public void punish(String uid, int violationCount, PunishManager punishManager) {
            //违规1~3次,警告制裁
            System.out.println("警告制裁");
        }
    }
    
    public class MidPunishState implements PunishState {
        @Override
        public void punish(String uid, int violationCount, PunishManager punishManager) {
            //违规3次以上,封号三天
            System.out.println("封号三天");
        }
    }
    
    public class HeightPunishState implements PunishState {
        @Override
        public void punish(String uid, int violationCount, PunishManager punishManager) {
            //违规5次以上,封号一周
            System.out.println("封号一周");
        }
    }
    
    public class BlackPunishState implements PunishState {
        @Override
        public void punish(String uid, int violationCount, PunishManager punishManager) {
            //违规10次,永久封号
            System.out.println("永久封号");
        }
    }
    

    入口类

    public class Main {
        public static void main(String[] args) {
            PunishManager punishManager = new PunishManager();
    
            for (int i = 1; i <= 10; i++) {
                punishManager.punish("Kevin");
            }
        }
    }
    

    运行结果:


    优点

    • 封装了转换规则
    • 结构清晰,提高可维护性
    • 不同状态对应的不同行为放到单独类中,方便增加新的状态,只需改变对象状态即可改变对象行为

    缺点

    • 增加了类和对象的个数
    • 状态模式对“开闭原则”的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。

    相关文章

      网友评论

        本文标题:设计模式-状态模式

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