Java设计模式(23):状态模式

23,状态模式

23.1,问题引入_APP抽奖活动

  • 提供一种抽奖活动,每一次抽奖扣除用户50积分,且中奖概率为10%,奖品数量固定,送完为止
  • 活动存在四种状态:
    • 不能抽奖:未进行积分兑换
    • 可以抽奖:已经进行积分兑换。抽奖完成后,如果未中奖,转到不能抽奖;如果中奖,转到发放奖品
    • 发放奖品:对中奖用户发放奖品。奖品发送后,如果还有剩余奖品,转到不能抽奖;如果奖品已经送完,转到奖品领完
    • 奖品领完:奖品全部领完
  • 这种需求可以通过状态模式完成

23.2,基本介绍

  • 状态模式(State Pattern):主要是解决对象在多种间转换时,需要对外输出不同行为的问题。状态和行为是一一对应的,状态之间可以相互切换
  • 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类
  • 状态模式也是一种行为型模式

23.3,类图

在这里插入图片描述

  • State:状态类顶层接口,定义了状态全流程的基本行为模式;再状态接口下可以加一层状态类的异常实现,并用具体状态类继承该类通过方法重写进行具体实现
  • XXXState:状态类具体实现类,根据各自状态对对应的方法进行实现,实现业务功能
  • StateTypeEnum:状态类对应枚举类,用于进行状态合法性判断
  • Activity:状态类的环境角色,组合 State 状态类,用户进行各个状态之间切换,继续进行业务流转

23.4,代码实现

  • StateTypeEnum:状态类枚举

    package com.self.designmode.state;
    
    /**
     * 状态模式: 抽奖流程状态枚举类
     * @author PJ_ZHANG
     * @create 2020-12-17 17:26
     **/
    public enum StateTypeEnum {
    
        // 0:不能抽奖, 1:可以抽奖, 2:抽奖成功,发放奖品, 3:奖品发放结束
        NON("0"), CAN("1"), PROVIDE("2"), COMPLETE("3");
    
        private String type;
    
        private StateTypeEnum(String type) {
            this.type = type;
        }
    
        public String getStrValue() {
            return this.type;
        }
    }
    
  • State:状态类顶层接口

    package com.self.designmode.state;
    
    /**
     * 状态模式: 顶层状态类接口
     * @author PJ_ZHANG
     * @create 2020-12-17 17:26
     **/
    public interface State {
    
        /**
         * 扣除积分
         * @param activity
         */
        void lessPoints(Activity activity);
    
        /**
         * 抽奖
         * @param activity
         */
        boolean raffle(Activity activity);
    
        /**
         * 发放奖品类
         * @param activity
         */
        void awards(Activity activity);
    
        /**
         * 获取状态类型值
         * @return
         */
        String getStateType();
    }
    
  • NonState:具体状态类,初始状态类,不能抽奖,需要进行积分兑换

    package com.self.designmode.state;
    
    /**
     * 状态模式: 不能抽奖类
     * @author PJ_ZHANG
     * @create 2020-12-17 17:33
     **/
    public class NonState implements State {
    
        @Override
        public void lessPoints(Activity activity) {
            if (!StateTypeEnum.NON.getStrValue().equals(activity.getStateType())) {
                return;
            }
            if (activity.getCount() <= 0) {
                throw new RuntimeException("兑换积分失败, 领完了...");
            }
            // 扣除积分即可以抽奖
            System.out.println("扣除了积分, 有了一次抽奖机会");
            // 变更状态为可抽奖
            activity.setState(new CanState());
        }
    
        @Override
        public boolean raffle(Activity activity) {
            throw new RuntimeException("状态不符合....");
        }
    
        @Override
        public void awards(Activity activity) {
            throw new RuntimeException("状态不符合....");
        }
    
        @Override
        public String getStateType() {
            return StateTypeEnum.NON.getStrValue();
        }
    }
    
  • CanState:具体状态类,抽检类,积分兑换完成,可进行抽奖

    package com.self.designmode.state;
    
    import java.util.Random;
    
    /**
     * 状态模式: 可以抽奖类
     * @author PJ_ZHANG
     * @create 2020-12-17 17:33
     **/
    public class CanState implements State {
    
        @Override
        public void lessPoints(Activity activity) {
            throw new RuntimeException("状态不符合....");
        }
    
        @Override
        public boolean raffle(Activity activity) {
            if (!activity.getStateType().equals(StateTypeEnum.CAN.getStrValue())) {
                throw new RuntimeException("状态不符合....");
            }
            // 进行抽奖
            int data = new Random().nextInt(10);
            if (data == 0) {
                System.out.println("抽奖成功, 可以进行领奖");
                activity.setState(new ProvideState());
                return true;
            } else {
                System.out.println("抽奖失败, 继续花积分吧");
                activity.setState(new NonState());
                return false;
            }
        }
    
        @Override
        public void awards(Activity activity) {
            throw new RuntimeException("状态不符合....");
        }
    
        @Override
        public String getStateType() {
            return StateTypeEnum.CAN.getStrValue();
        }
    }
    
  • ProvideState:具体状态类,奖品下发类,抽奖中奖,进行奖品下发

    package com.self.designmode.state;
    
    /**
     * 状态模式: 抽奖成功, 发放奖品
     * @author PJ_ZHANG
     * @create 2020-12-17 17:33
     **/
    public class ProvideState implements State {
    
        @Override
        public void lessPoints(Activity activity) {
            throw new RuntimeException("状态不符合....");
        }
    
        @Override
        public boolean raffle(Activity activity) {
            throw new RuntimeException("状态不符合....");
        }
    
        @Override
        public void awards(Activity activity) {
            if (!StateTypeEnum.PROVIDE.getStrValue().equals(activity.getStateType())) {
                throw new RuntimeException("状态不符合....");
            }
            System.out.println("发放奖品");
            activity.subCount();
            if (activity.getCount() <= 0) {
                activity.setState(new NonState());
            } else {
                activity.setState(new CompleteState());
            }
        }
    
        @Override
        public String getStateType() {
            return StateTypeEnum.PROVIDE.getStrValue();
        }
    }
    
  • CompleteState:具体状态类,奖品发放完成类,也就是状态流转结束状态

    package com.self.designmode.state;
    
    /**
     * 状态模式: 奖品发放完成类
     * @author PJ_ZHANG
     * @create 2020-12-17 17:33
     **/
    public class CompleteState implements State {
    
        @Override
        public void lessPoints(Activity activity) {
            System.out.println("奖品发放完成...");
        }
    
        @Override
        public boolean raffle(Activity activity) {
            throw new RuntimeException("状态不符合....");
        }
    
        @Override
        public void awards(Activity activity) {
            throw new RuntimeException("状态不符合....");
        }
    
        @Override
        public String getStateType() {
            return StateTypeEnum.COMPLETE.getStrValue();
        }
    }
    
  • Activity:状态流转控制类

    package com.self.designmode.state;
    
    /**
     * 状态模式: 流程控制, 抽奖流程类
     * @author PJ_ZHANG
     * @create 2020-12-17 17:30
     **/
    public class Activity {
    
        private State state;
    
        private int count;
    
        public Activity(int count) {
            this.count = count;
            state = new NonState();
        }
    
        /**
         * 扣除积分,兑换抽奖机会
         */
        public void lessPoints() {
            state.lessPoints(this);
        }
    
        /**
         * 抽奖
         */
        public boolean raffle() {
            return state.raffle(this);
        }
    
        /**
         * 发放奖品
         */
        public void awards() {
           state.awards(this);
        }
    
        public void setState(State state) {
            this.state = state;
        }
    
        public String getStateType() {
            return state.getStateType();
        }
    
        public void subCount() {
            count--;
        }
    
        public int getCount() {
            return count;
        }
    
    }
    
  • Client:客户端

    package com.self.designmode.state;
    
    /**
     * 状态模式, 客户端
     * @author PJ_ZHANG
     * @create 2020-12-17 17:54
     **/
    public class Client {
    
        public static void main(String[] args) {
            Activity activity = new Activity(1);
            // 抽10次, 可能抽奖失败
            for (int i = 0; i < 10; i++) {
                activity.lessPoints();
                boolean result = activity.raffle();
                if (result) {
                    activity.awards();
                }
            }
        }
    
    }
    

23.5,状态模式的注意事项和细节

  • 代码具有很高的可读性,状态模式将每个状态的行为封装到一个对应的类中
  • 方便维护,代码中去除了if-else分支,用不同的状态类将业务流转串联起来,不需要每次执行的之后进行分支判断,提高代码的容错率
  • 符合OCP原则,容易对状态进行灵活变更
  • 状态模式容易产生很多类,每个状态都会对应一个类,当状态过多的时候,会加大维度难度
  • 应用场景:当一个事件或者对象有多种状态,且存在状态间切换,对不同的状态又存在不同的行为的时候,可以使用状态模式
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值