深入理解23种设计模式(21) -- 状态模式

@[TOC]

介绍

  1. 状态模式 (State pattern): 它主要是用来解决对象在多种状态之间的转换,需要对外输出不同的行为的问题,状态和行为是一一对应的,状态之间可以互相转换。
  2. 当一个对象的内在状态改变时,允许改变其行为,这个对象看起来是改变了其他类。 在这里插入图片描述
  • Context : 为环境角色,用于维护一个ConcreteState子类的实例,这个实例定义当前的状态。
  • State : 为抽象状态角色,定义一个接口以封装与Context的一个特定接口状态相关的行为。
  • ConcreateState : 是具体状态角色,每一个子类实现一个与Context的一个状态相关的行为。

案例

抽奖活动:

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

创建 RaffleActivity 类 相当于状态模式中的 Context

public class RaffleActivity {

    State state;

    int count = 0;

    State noRaffleState = new NoRaffleState(this);
    State canRaffleState = new CanRaffleState(this);
    State dispenseState = new DispenseState(this);
    State dispenseOutState = new DispenseOutState(this);

    public RaffleActivity(int count) {
        this.state = getNoRaffleState();
        this.count = count;
    }



    public void debuctMoney(){
        state.deductMoney();
    }

    public void raffle(){
        if(state.raffle()){
            state.dispensePrize();
        }
    }

    public int getCount(){
        int curCount = count;
        count-- ;
        return curCount;
    }

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

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

    State getNoRaffleState() {
        return noRaffleState;
    }

    public State getCanRaffleState() {
        return canRaffleState;
    }

    public void setCanRaffleState(State canRaffleState) {
        this.canRaffleState = canRaffleState;
    }

    public State getDispenseState() {
        return dispenseState;
    }

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

    public State getDispenseOutState() {
        return dispenseOutState;
    }

    public void setDispenseOutState(State dispenseOutState) {
        this.dispenseOutState = dispenseOutState;
    }

    public State getState() {
        return state;
    }

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

创建抽象接口

public abstract class State {

    /**
     * 扣除积分
     */
    public abstract void deductMoney();

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

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



}

创建 初始化抽奖活动 NoRaffleState 类继承 State

public class NoRaffleState extends State{

    //初始化活动引用
    RaffleActivity raffleActivity;

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

    @Override
    public void deductMoney() {
        System.out.println("扣除50积分可以抽奖");
        raffleActivity.setState(raffleActivity.getCanRaffleState());
    }

    @Override
    public boolean raffle() {
        System.out.println("输入积分才能抽奖");
        return false;
    }

    @Override
    public void dispensePrize() {
        System.out.println("当前状态不能发放奖品");
    }
}

创建 正在抽奖活动 CanRaffleState 类继承 State

public class CanRaffleState extends State{

    //初始化活动引用
    RaffleActivity raffleActivity;

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

    @Override
    public void deductMoney() {
        System.out.println("已经扣取过积分");
    }

    @Override
    public boolean raffle() {
        System.out.println("正在抽奖 ……");
        Random r = new Random();
        int num = r.nextInt(10);
        if(num == 0){
            System.out.println("中奖了");
            raffleActivity.setState(raffleActivity.getDispenseState());
            //发放奖品
            return true;
        }else {
            System.out.println("很遗憾,没有中奖");
            raffleActivity.setState(raffleActivity.getNoRaffleState());
            return false;
        }
    }

    @Override
    public void dispensePrize() {
        System.out.println("不能发放奖品");
    }
}

创建 分发抽奖活动 DispenseState 类继承 State

public class DispenseState extends State{

    //初始化活动引用
    RaffleActivity raffleActivity;

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

    @Override
    public void deductMoney() {
        System.out.println("不能扣除积分");
    }

    @Override
    public boolean raffle() {
        System.out.println("不能抽奖");
        return false;
    }

    @Override
    public void dispensePrize() {
        if (raffleActivity.getCount() > 0){
            raffleActivity.setState(raffleActivity.getNoRaffleState());
        }else{
            System.out.println("奖品发完了");
            raffleActivity.setState(raffleActivity.getDispenseState());
        }
    }
}

创建 抽奖活动分发完成 DispenseOutState 类继承 State

public class DispenseOutState extends State{

    //初始化活动引用
    RaffleActivity raffleActivity;

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


    @Override
    public void deductMoney() {
        System.out.println("奖品发送完了,下次参加");
    }

    @Override
    public boolean raffle() {
        System.out.println("奖品发送完了,下次参加");
        return false;
    }

    @Override
    public void dispensePrize() {
        System.out.println("奖品发送完了,下次参加");
    }
}

客户端

public class Client {

    public static void main(String[] args) {
        RaffleActivity raffleActivity = new RaffleActivity(1);
        for (int i = 1; i < 10; i++) {
            System.out.println("----------第" +i+"次抽奖---------");
            //扣积分
            raffleActivity.debuctMoney();
            raffleActivity.raffle();
        }
    }
}

在这里插入图片描述

优点和缺点

优点:

1)结构清晰,避免了过多的switch…case或if…else语句的使用

2)很好的体现了开闭原则和单一职责原则,想要增加状态就增加子类,想要修改状态就修改子类即可
3)封装性非常好,状态变化放置到了类的内部来实现,外部调用不需要知道类内部如何实现状态和行为的变换

缺点:

 1)子类会太多,也即类膨胀

适用场景:

 1)  一行为随状态改变而改变的场景 如 : 一日从早到晚自身的状态,比如工作状态、学习状态等等
 2)  条件、分支判断语句的替代者


github Demo地址 : ~~~传送门~~~

个人博客地址:http://blog.yanxiaolong.cn/

end
  • 作者:yxl(联系作者)
  • 发表时间:2021-02-25 22:30
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 转载声明:如果是转载栈主转载的文章,请附上原文链接
  • 公众号转载:请在文末添加作者公众号二维码(公众号二维码见右边,欢迎关注)
  • 评论