尚硅谷设计模式学习(二十二)状态模式

以抽奖活动引出状态模式

假如每参加一次抽奖活动要扣除用户 50 积分,中奖概率是 10%,奖品数量固定,抽完就不能抽奖。
活动有四个状态:可以抽奖、不能抽奖、发放奖品和奖品领完

活动的四个状态转换关系图

一、状态模式

1、基本介绍

状态模式(State  Pattern):它主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。状态和行为是一一对应的,状态之间可以相互转换。

当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变了其类

  • Context:环境角色,用于维护  State 实例,这个实例定义当前状态
  • State:是抽象状态角色,封装与 Context 的一个特点接口相关行为
  • ConcreteState:具体的状态角色,每个子类实现一个与 Context 的一个状态相关行为 

2、代码实现

具体思路

 

根据抽奖状态关系转换图,可以在抽象状态中定义三个方法

  • 扣除积分(每次抽奖前都要扣除积分)
  • 是否中奖(抽奖时有两种情况,中奖和不中奖)
  • 领取奖品(领取奖品有两种情况,有奖品和没有奖品)

抽象状态类

public abstract class State {
    /**
     * 扣除积分 -50
     */
    public abstract void deductIntegral();

    /**
     * 是否抽中奖品
     * @return
     */
    public abstract boolean raffle();

    /**
     * 发放奖品
     */
    public abstract void dispensePrize();
}

不能抽奖状态

提前说明:RaffleActivity为抽奖活动类,里面聚合了四种抽奖状态,在执行这三个方法时会根据情况改变状态。

//不能抽奖状态
public class NoRaffleState extends State {

    private RaffleActivity raffleActivity;

    public NoRaffleState(RaffleActivity raffleActivity){
        this.raffleActivity = raffleActivity;
    }

    //扣除积分 -50
    @Override
    public void deductIntegral() {
        System.out.println("扣除50积分成功,您可以抽奖了");
        //状态转换:不能抽奖状态 ===> 抽奖状态
        raffleActivity.setState(raffleActivity.getRaffleState());
    }

    //是否抽中奖品
    @Override
    public boolean raffle() {
        System.out.println("对不起,扣除积分才能抽奖");
        return false;
    }

    //发放奖品
    @Override
    public void dispensePrize() {
        System.out.println("没参与抽奖,不能发放奖品");
    }
}

抽奖状态

//抽奖状态
public class RaffleState extends State {

    private RaffleActivity raffleActivity;

    public RaffleState(RaffleActivity raffleActivity) {
        this.raffleActivity = raffleActivity;
    }

    //扣除积分 -50
    @Override
    public void deductIntegral() {
        System.out.println("已经扣过积分,参与抽奖吧");
    }

    //是否抽中奖品
    @Override
    public boolean raffle() {
        System.out.println("要抽奖啦");
        int i = new Random().nextInt(5);
        //只有 25% 的可能性抽中奖品
        if(i == 1){
            //抽奖状态 ===> 发放奖品状态
            raffleActivity.setState(raffleActivity.getDispenseState());
            return true;
        }else {
            System.out.println("没抽中奖品,再接再厉");
            //抽奖状态 ===> 不能抽奖状态
            raffleActivity.setState(raffleActivity.getNoRaffleState());
            return false;
        }
    }

    //发放奖品
    @Override
    public void dispensePrize() {
        System.out.println("没中奖,不给奖品");
    }
}

发放奖品状态

//发放奖品状态
public class DispenseState extends State {

    private RaffleActivity raffleActivity;

    public DispenseState(RaffleActivity raffleActivity) {
        this.raffleActivity = raffleActivity;
    }

    //扣除积分 -50
    @Override
    public void deductIntegral() {
        System.out.println("发奖品呢,扣什么积分");
    }

    //是否抽中奖品
    @Override
    public boolean raffle() {
        System.out.println("你已经在领奖了,还抽奖干嘛");
        return false;
    }

    //发放奖品
    @Override
    public void dispensePrize() {
        int count = raffleActivity.getCount();
        if(count > 0){
            System.out.println("恭喜你,领取奖品成功,奖品剩余 " + --count + "个");
            //领奖状态 ===> 不能抽奖状态
            raffleActivity.setState(raffleActivity.getNoRaffleState());
            raffleActivity.setCount(count);
        }else {
            System.out.println("不好意思,没有奖品了");
            //领奖状态 ===> 奖品领完状态
            raffleActivity.setState(raffleActivity.getDispenseOutState());
        }
    }
}

奖品领完状态 

//奖品领完状态
public class DispenseOutState extends State {

    private RaffleActivity raffleActivity;

    public DispenseOutState(RaffleActivity raffleActivity) {
        this.raffleActivity = raffleActivity;
    }

    //扣除积分 -50
    @Override
    public void deductIntegral() {
        System.out.println("奖品没了,就不扣您的积分了");
    }

    //是否抽中奖品
    @Override
    public boolean raffle() {
        System.out.println("奖品都没了,您还抽什么奖啊!");
        return false;
    }

    //发放奖品
    @Override
    public void dispensePrize() {
        System.out.println("奖品都没了,不用来领奖了!");
    }
}

抽奖活动类

public class RaffleActivity {

    //抽奖状态
    private State state;
    //奖品数量
    private int count;

    //不能抽奖状态
    private NoRaffleState noRaffleState = new NoRaffleState(this);
    //能抽奖状态
    private RaffleState raffleState = new RaffleState(this);
    //发放奖品状态
    private DispenseState dispenseState = new DispenseState(this);
    //奖品领完状态
    private DispenseOutState dispenseOutState = new DispenseOutState(this);

    public RaffleActivity(int count) {
        System.out.println("快来玩啊,抽奖活动开始了");
        // 初始化状态为 ===> 不能抽奖状态
        this.state = this.noRaffleState;
        this.count = count;
    }

    //扣除积分;
    public void deductIntegral(){
        state.deductIntegral();
    }

    //抽奖;
    public void raffle(){
        if(state.raffle()){
            //抽中了就做好发奖品的准备吧
            state.dispensePrize();
        }
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public NoRaffleState getNoRaffleState() {
        return noRaffleState;
    }

    public void setNoRaffleState(NoRaffleState noRaffleState) {
        this.noRaffleState = noRaffleState;
    }

    public RaffleState getRaffleState() {
        return raffleState;
    }

    public void setRaffleState(RaffleState raffleState) {
        this.raffleState = raffleState;
    }

    public DispenseState getDispenseState() {
        return dispenseState;
    }

    public void setDispenseState(DispenseState dispenseState) {
        this.dispenseState = dispenseState;
    }

    public DispenseOutState getDispenseOutState() {
        return dispenseOutState;
    }

    public void setDispenseOutState(DispenseOutState dispenseOutState) {
        this.dispenseOutState = dispenseOutState;
    }
    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

测试

public class Client {
    public static void main(String[] args) {
        RaffleActivity raffleActivity = new RaffleActivity(2);
        for (int i = 1; i <= 10; i++){
            System.out.println("-----第" + i + "次抽奖-----");
            raffleActivity.deductIntegral();
            raffleActivity.raffle();
        }
    }
}

结果

快来玩啊,抽奖活动开始了
-----第1次抽奖-----
扣除50积分成功,您可以抽奖了
要抽奖啦
恭喜你,领取奖品成功,奖品剩余 1个
-----第2次抽奖-----
扣除50积分成功,您可以抽奖了
要抽奖啦
没抽中奖品,再接再厉
-----第3次抽奖-----
扣除50积分成功,您可以抽奖了
要抽奖啦
恭喜你,领取奖品成功,奖品剩余 0个
-----第4次抽奖-----
扣除50积分成功,您可以抽奖了
要抽奖啦
没抽中奖品,再接再厉
-----第5次抽奖-----
扣除50积分成功,您可以抽奖了
要抽奖啦
没抽中奖品,再接再厉
-----第6次抽奖-----
扣除50积分成功,您可以抽奖了
要抽奖啦
没抽中奖品,再接再厉
-----第7次抽奖-----
扣除50积分成功,您可以抽奖了
要抽奖啦
没抽中奖品,再接再厉
-----第8次抽奖-----
扣除50积分成功,您可以抽奖了
要抽奖啦
没抽中奖品,再接再厉
-----第9次抽奖-----
扣除50积分成功,您可以抽奖了
要抽奖啦
不好意思,没有奖品了
-----第10次抽奖-----
奖品没了,就不扣您的积分了
奖品都没了,您还抽什么奖啊!

二、状态模式的注意事项和细节

1)代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中

2)方便维护。将容易产生问题的 if-else  语句删除了,如果把每个状态的行为都放到一个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多  if-else 语句,而且容易出错。

3)符合“开闭原则”。容易增删状态

4)会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度

应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候,可以考虑使用状态模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鲁蛋儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值