Java设计模式——状态模式

Java设计模式之状态模式

首先你可能会想用int值存储状态,实现状态切换,Java中很多地方都像这样使用,特别时并发JUC中,但是我们的设计模式将提供一个更符合设计原则,更有弹性的状态模式。(JUC中使用int存储状态是因为不想让一个并发类的实现需要依赖很多的状态类,int值已经可以满足需求,状态模式更多是针对系统的设计)

状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。

把对象设计成一个接口,该接口定义状态共同的方法,具体的状态的实现就实现该接口。

  1. 为状态定义一个接口(可能为抽象类),接口中的方法定义一些动作
  2. 为每个状态实现状态类,重写各个状态不同的行为实现
  3. Context中将操作委托给状态

但是状态模式有一个缺点就是,状态和状态之间依赖太强了,但是这种操作提供的是一个更有弹性的设计,而且Context只需要知道我需要提交的请求而不需要知道它是怎么执行的,因为实现是有状态内部负责的。

Head first 设计模式例子

一个糖果机售卖糖果,你放入15分就可以后转动转盘就可以获取一个糖果,但是也有糖果售完的情况。

我们有放入钱转动转盘放出糖果退款四个操作,这些操作接口由一个接口或者抽象类定义(抽象类可实现默认方法),这个类就是状态抽象类或者状态接口类

该糖果机这里就有以下4个状态:

  • 没有放钱的状态——NoMoney
  • 放入钱的状态——HasMoney
  • 售出糖果的状态——Sold
  • 售完的状态——SoldOut

每一个状态都有对应操作的不同实现,像NoMoney状态就不可以操作退款和放出糖果,转动转盘也没有糖果掉出,所以我们可以使用抽象类的默认方法(无法进行该操作)或者使用重写的方法实现更人性化的操作。

实现了对修改关闭,对扩展开放的原则,有新的状态只需新添加一个类并实现其方法

  • State
public abstract class State {
    protected void insertMoney(){
        System.out.println("错误的请求");
    }
    protected void returnMoney(){
        System.out.println("错误的请求");
    }
    protected void turnCrank(){
        System.out.println("错误的请求");
    }
    protected void distribute(){
        System.out.println("错误的请求");
    }
}
  • HasMoney
public class HasMoney extends State{
    private CandyMachine candyMachine;
    public HasMoney(CandyMachine candyMachine){
        this.candyMachine = candyMachine;
    }
    protected void insertMoney() {
        System.out.println("已经放入15分了。请不要再次放入");
    }
    protected void turnCrank() {
        System.out.println("你转动了轮盘,等待糖果放出-------");
        candyMachine.setCurrentState(candyMachine.getSoldSate());
    }
}
  • NoMoney
public class NoMoney extends State{
    private CandyMachine candyMachine;
    public NoMoney(CandyMachine candyMachine){
        this.candyMachine = candyMachine;
    }
    @Override
    protected void insertMoney() {
        System.out.println("你放入了15分,请你转动轮盘来获取糖果-------");
        candyMachine.setCurrentState(candyMachine.getHasMoneyState());
    }
}
  • Sold
public class Sold extends State{
    private CandyMachine candyMachine;
    public Sold(CandyMachine candyMachine){
        this.candyMachine = candyMachine;
    }
    @Override
    protected void distribute() {
        if(candyMachine.getCount()>0){
            System.out.println("您好,这里是一个糖果-------");
            candyMachine.setCount((candyMachine.getCount()-1));
            candyMachine.setCurrentState(candyMachine.getNoMoneyState());
        }else {
            System.out.println("您好,不好意思,我们的糖果售空了,稍后将退钱给你-------");
            candyMachine.setCurrentState(candyMachine.getSoldOutSate());
            candyMachine.getCurrentState().returnMoney();
        }
    }
}
  • SoldOut
public class SoldOut extends State{
    private CandyMachine candyMachine;
    public SoldOut(CandyMachine candyMachine){
        this.candyMachine = candyMachine;
    }
    @Override
    protected void returnMoney() {
        System.out.println("您好,不好意思,这里是给您退的15分-------");
        candyMachine.setCurrentState(candyMachine.getNoMoneyState());
    }
}
  • CandyMachine:操作糖果机
@Data
public class CandyMachine {
    private State noMoneyState;
    private State hasMoneyState;
    private State soldSate;
    private State soldOutSate;
    //糖果数量
    private int count;
    private State currentState;
    public CandyMachine(int initCandyCount) {
        count = initCandyCount;
        noMoneyState = new NoMoney(this);
        hasMoneyState = new HasMoney(this);
        soldSate = new Sold(this);
        soldOutSate = new SoldOut(this);
        currentState = noMoneyState;
    }
    public void purchaseOneCandy(){
        currentState.insertMoney();
        currentState.turnCrank();
        currentState.distribute();
    }
}
  • 测试
public class TestMain {
    public static void main(String[] args) {
        CandyMachine candyMachine = new CandyMachine(2);
        candyMachine.purchaseOneCandy();
        System.out.println("\n");
        candyMachine.purchaseOneCandy();
        System.out.println("\n");
        candyMachine.purchaseOneCandy();
    }
}
  • 输出
你放入了15分,请你转动轮盘来获取糖果-------
你转动了轮盘,等待糖果放出-------
您好,这里是一个糖果-------

你放入了15分,请你转动轮盘来获取糖果-------
你转动了轮盘,等待糖果放出-------
您好,这里是一个糖果-------

你放入了15分,请你转动轮盘来获取糖果-------
你转动了轮盘,等待糖果放出-------
您好,不好意思,我们的糖果售空了,稍后将退钱给你-------
您好,不好意思,这里是给您退的15分-------

状态模式和策略模式

你可以看到,状态模式的类图和策略模式基本一致,它俩很相同,但是最大的区别是意图不同。

  • 状态模式将行为封装在状态中,Context的行为委托于状态对象,随着时间改变自己的状态
  • 策略模式是将行为封装起来,使用委托决定使用哪个行为

Context有多个实例,共享状态对象:状态对象声明为静态的,通过引用传入

代码地址:Github状态模式


Java设计模式|策略模式

Java设计模式|观察者模式

Java设计模式|装饰者模式

Java设计模式|工厂模式

Java设计模式|命令模式

Java设计模式|适配器模式和外观模式

Java设计模式|模板方法模式

Java设计模式|迭代器模式和组合模式

Java设计模式|状态模式

Java设计模式|代理模式

Java设计模式|单例模式

Java设计模式|备忘录模式

Java设计模式|访问者模式

Java设计模式|复合模式

Java设计模式|桥接模式

Java设计模式|生成器模式

Java设计模式|享元模式/蝇量模式

Java设计模式|原型模式

Java设计模式|责任链模式

Java设计模式|中介者模式

  • 本文作者: dzou | 微信:17856530567
  • 本文链接: http://www.dzou.top/post/94ac76a6.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
  • 并保留本声明和上方二维码。感谢您的阅读和支持!