设计模式从入门到放弃(二十)状态模式

状态模式 State Pattern 属于行为模式,主要用来解决对象在多状态切换时,需要对外输出不同行为的问题。状态和行为一一对应,状态之间可以相互转换。使用场景在于代码中有大量对对象状态相关的判断的条件语句的时候较为适合。

UML

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w7lwh3Vw-1589449857320)(C:\Users\denglw\AppData\Roaming\Typora\typora-user-images\image-20200514161230424.png)]

角色分析

Context 上下文对象 用于维护State的实例 维护当前的状态

State 状态抽象接口 封装了跟对象相关的一系列行为

ConcreteState 具体的状态角色,子类可以根据需要根据不同的状态实现自己的处理行为

代码实现

类似抽奖活动一样,抽奖的活动主要有3个步骤 消耗抽奖次数deduce 抽奖raffle 兑换奖品dispense相当于State中的抽象行为,状态可以分为可以抽奖状态,发奖品状态,不可抽奖状态,奖品发放完毕状态,对于不同的状态对以上3个行为的实现逻辑都不同

// 抽象状态接口 封装了一个对象所有的行为 如抽奖活动 有3个行为 扣积分 抽奖 发奖3个行为
public interface State {

    void deduce();

    void raffle();

    void dispense();
}
// 抽象状态实现 所有方法都是空实现 为了让子类继承子类根据自己需要实现自己的方法
public class AbstractState implements State {
    // 聚合一个Context 对象 这里是抽奖活动
    RaffleActivity raffleActivity;

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

    @Override
    public void deduce() {

    }

    @Override
    public void raffle() {

    }

    @Override
    public void dispense() {

    }
}

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

    public NoRaffleState(RaffleActivity raffleActivity) {
        super(raffleActivity);
    }

    @Override
    public void deduce() {
        System.out.println("当前已经不能抽奖了...");
        raffleActivity.setCurrentState(raffleActivity.noRaffleState);
    }

}

// 可以抽奖状态 只需要实现raffle抽奖方法即可
public class CanRaffleState extends AbstractState {

    public CanRaffleState(RaffleActivity raffleActivity) {
        super(raffleActivity);
    }

    @Override
    public void raffle() {
        int random = ThreadLocalRandom.current().nextInt(10);
        if (random == 0) {
            System.out.println(" 恭喜抽中了! ");
            raffleActivity.setCurrentState(raffleActivity.dispenseState);
        } else {
            System.out.println(" 没有抽中..");
            raffleActivity.setCurrentState(raffleActivity.canRaffleState);
        }
    }

}

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

    public DispenseState(RaffleActivity raffleActivity) {
        super(raffleActivity);
    }


    @Override
    public void dispense() {
        int remind = --raffleActivity.count;
        if (remind < 0) {
            System.out.println("奖品已经发完了");
            // 没奖品改为不能抽奖状态
            raffleActivity.setCurrentState(raffleActivity.noRaffleState);
        } else {
            System.out.println("领取奖品.!");
            raffleActivity.setCurrentState(raffleActivity.canRaffleState);
        }
    }
}

// 活动对象 Context 
public class RaffleActivity {
    private State currentState;

    protected int count;

    // 核心 在创建状态对象的同时把自己聚合到对象状态里面
    protected State noRaffleState = new NoRaffleState(this);
    protected State dispenseState = new DispenseState(this);
    protected State canRaffleState = new CanRaffleState(this);

    public RaffleActivity(int count) {
        this.currentState = this.canRaffleState;
        this.count = count;
    }

    public State getCurrentState() {
        return currentState;
    }

    public void setCurrentState(State currentState) {
        this.currentState = currentState;
    }

    public void play() {
        currentState.deduce();
        currentState.raffle();
        currentState.dispense();
    }
}
public class StateTest {

    public static void main(String[] args) {
        RaffleActivity raffleActivity = new RaffleActivity(1);
        for (int i = 0; i < 300; i++) {
            System.out.println("======第" + i + "次抽奖========");
            raffleActivity.play();
            System.out.println("==============");
        }
    }

}

使用细节

  • 状态模式代码可读性强,将不同状态的不同的行为分装到对应的类中
  • 方便维护不用写if-else语句 符合OCP原则 容易扩展
  • 缺点在于如果状态和行为过多会导致状态类过多,行为实现逻辑复杂
  • 应用场景适合在一个事件或对象存在多种状态,状态之间会相互切换的的时候,对不同状态有不同行为的时候适合使用状态模式如流程审核,工作流等适合使用状态模式

猜你喜欢

转载自blog.csdn.net/woshiwjma956/article/details/106125252
今日推荐