• 行为型设计模式


    基本介绍

    状态模式(State Pattern)主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题,类的行为是基于它的状态改变的。

    模式结构

    Context(环境角色):用于维护 State 实例,这个实例定义当前状态

    State(抽象状态):定义一个接口以封装与 Context 的一个特定状态相关的行为

    ConcreteState(具体状态):每一子类实现一个与 Context 的一个状态相关的行为

    举例说明

    我们以抽奖的场景作为例子,流程如下:

    定义一个抽象状态:State

    public interface State {
        RuntimeException EXCEPTION = new RuntimeException("不能执行此操作");
    
        /**
         * 报名
         */
        default void signUp() {
            throw EXCEPTION;
        }
    
        /**
         * 抽奖
         */
        default boolean raffle() {
            throw EXCEPTION;
        }
    
        /**
         * 发奖品
         */
        default void sendPrize() {
            throw EXCEPTION;
        }
    }
    
    

    具体状态1:不能抽奖

    public class NotRaffleState implements State {
    
        private RaffleActivity activity;
    
        public NotRaffleState(RaffleActivity activity) {
            this.activity = activity;
        }
    
        @Override
        public void signUp() {
            //如果没有奖品,直接进入无奖品状态
            if (!activity.hasPrize()) {
                activity.setState(activity.getNoPrizeState());
                return;
            }
            System.out.println("报名成功,可以抽奖了");
            activity.setState(activity.getCanRaffleState());
        }
    }
    

    具体状态2:可以抽奖

    public class CanRaffleState implements State {
    
        private RaffleActivity activity;
    
        public CanRaffleState(RaffleActivity activity) {
            this.activity = activity;
        }
    
        @Override
        public boolean raffle() {
            //模拟五分之一的中奖几率
            int n = new Random().nextInt(5);
            if (n == 0) {
                //抽中,进入发放奖品的状态
                System.out.println("恭喜你,抽中了");
                activity.setState(activity.getSendPrizeState());
                return true;
            } else {
                //未抽中,回到初始状态
                System.out.println("很遗憾,没有抽中");
                activity.setState(activity.getNotRaffleState());
                return false;
            }
        }
    }
    

    具体状态3:发放奖品

    public class SendPrizeState implements State {
    
        private RaffleActivity activity;
    
        public SendPrizeState(RaffleActivity activity) {
            this.activity = activity;
        }
    
        @Override
        public void sendPrize() {
            int count = activity.getCount();
            //没有奖品了
            if (count <= 0) {
                System.out.println("奖品没有了,下次再来吧");
                activity.setState(activity.getNoPrizeState());
            } else {
                activity.setCount(--count);
                System.out.println("奖品已发送");
                activity.setState(activity.getNotRaffleState());
            }
        }
    }
    

    具体状态4:奖品领完

    public class NoPrizeState implements State {
    
        private RaffleActivity activity;
    
        public NoPrizeState(RaffleActivity activity) {
            this.activity = activity;
        }
    
        @Override
        public void signUp() {
            System.out.println("奖品没有了,下次再来吧");
            System.exit(0);
        }
    
        @Override
        public boolean raffle() {
            System.out.println("奖品没有了,下次再来吧");
            System.exit(0);
            return false;
        }
    
        @Override
        public void sendPrize() {
            System.out.println("奖品没有了,下次再来吧");
            System.exit(0);
        }
    }
    

    环境角色:抽奖活动

    public class RaffleActivity {
        private State state;
        private int count;
        private State notRaffleState = new NotRaffleState(this);
        private State canRaffleState = new CanRaffleState(this);
        private State sendPrizeState = new SendPrizeState(this);
        private State noPrizeState = new NoPrizeState(this);
    
        public RaffleActivity(int count) {
            this.state = getNotRaffleState();
            this.count = count;
        }
    
        public void signUp() {
            state.signUp();
        }
    
        public void raffle() {
            if (state.raffle()) {
                state.sendPrize();
            }
        }
    
        public State getState() {
            return state;
        }
    
        public boolean hasPrize(){
            return count > 0;
        }
        //省略getter、setter
    }
    

    客户端

    public class Client {
        @Test
        public void test(){
            RaffleActivity activity = new RaffleActivity(1);
            for (int i = 0; i < 5; i++) {
                System.out.println("第" + (i + 1) + "次抽奖");
                activity.signUp();
                activity.raffle();
                System.out.println("------------------");
            }
        }
    }
    

    运行结果

    第1次抽奖
    报名成功,可以抽奖了
    很遗憾,没有抽中
    ------------------
    第2次抽奖
    报名成功,可以抽奖了
    恭喜你,抽中了
    奖品已发送
    ------------------
    第3次抽奖
    奖品没有了,下次再来吧
    

    模式分析

    优点:

    • 代码具有较强的可读性。状态模式将每个状态的行为封装到对应的一个类中
    • 方便维护。将容易产生问题的 if-else 语句删除了,如果把每个状态的行为都放到一个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多 if-else 语句,而且容易出错

    缺点:

    • 会产生很多类。每个状态都对应一个类,当状态过多时,维护难度变大
    • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱
    • 状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

    适用环境:

    • 行为随状态改变而改变的场景

    • 条件、分支语句的代替者

  • 相关阅读:
    淘宝从几百到千万级并发的十四次架构演进之路!
    19 个强大、有趣、好玩、又装B的 Linux 命令!
    Spring Boot实战:拦截器与过滤器
    初识zookeeper,linux 安装配置zookeeper
    Spring-boot:5分钟整合Dubbo构建分布式服务
    Spring-Boot:6分钟掌握SpringBoot开发
    Dubbo的使用及原理浅析.
    Java消息队列--ActiveMq 初体验
    关于Ubuntu 常用的简单指令
    IBM、HPUX、Solaris不同之处
  • 原文地址:https://www.cnblogs.com/songjilong/p/12894463.html
Copyright © 2020-2023  润新知