状态模式

1、状态模式的动机

2、责任链模式的定义

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

理解:

3、责任链模式的类结构图

image

模式中包含三个角色:抽象状态类(接口或者抽象类),具体状态类,环境类;

4、 优缺点和适用场景

优点:

缺点:

适用场景:

5、实例

6.1

例1:糖果售卖机
a、定义状态接口

/**
 * Desc:糖果自动售货机为例应用状态模式,共有四种行为:投币,退币,转轴,发放糖果
 * 五种状态:有币,无币,售出糖果,告罄,中奖赢家;
 * ------------------------------------
 * Author:XXXX
 * Date:2017/8/24
 * Time:11:16
 */
public interface State {
//  投币
    void insertQuarter();
//  退币
    void ejectQuarter();
//  转轴
    void turnCrank();
//  发放糖果
    void dispens

b、实现状态类

public class SoldState implements State {
    private CumballMachine cumballMachine;

    public SoldState(CumballMachine cumballMachine) {
        this.cumballMachine = cumballMachine;
    }

    public void insertQuarter() {
        System.out.println("SoldState,不允许投币");
    }

    public void ejectQuarter() {
        System.out.println("SoldState,不允许退币");
    }

    public void turnCrank() {
        System.out.println("SoldState,不允许转轴");
    }

    public void dispense() {
        cumballMachine.releaseBall();
        if (cumballMachine.getCount() > 0) {
            cumballMachine.setState(cumballMachine.getNoQuarter());
        } else {
            System.out.println("糖果售完");
            cumballMachine.setState(cumballMachine.getSoldOutState());
        }
    }
}
public class SoldOutState implements State {
    private CumballMachine cumballMachine;

    public SoldOutState(CumballMachine cumballMachine) {
        this.cumballMachine = cumballMachine;
    }

    public void insertQuarter() {
        System.out.println("SoldOutState,不可投币");
    }

    public void ejectQuarter() {
        System.out.println("SoldOutState,不可退币");
    }

    public void turnCrank() {
        System.out.println("SoldOutState,不可转轴");
    }

    public void dispense() {
        System.out.println("SoldOutState,不可发放糖果");
    }
}
public class NoQuarter implements State {
    private CumballMachine cumballMachine;

    public NoQuarter(CumballMachine cumballMachine) {
        this.cumballMachine = cumballMachine;
    }

    public void insertQuarter() {
        System.out.println("投入钱币,状态跳转到hasQuarter");
        cumballMachine.setState(cumballMachine.getHasQuarter());
    }

    public void ejectQuarter() {
        System.out.println("该状态没给钱,不能够退还钱币");
    }

    public void turnCrank() {
        System.out.println("该状态没给钱,不能够转轴");
    }

    public void dispense() {
        System.out.println("该状态没给钱,请先投币");
    }
}
/**
 * Desc:具体状态对象,将行为委托给具体的状态
 * ------------------------------------
 * Author:XXXX
 * Date:2017/8/24
 * Time:11:27
 */
public class HasQuarter implements State {
    private CumballMachine cumballMachine;

    public HasQuarter(CumballMachine cumballMachine) {
        this.cumballMachine = cumballMachine;
    }
    public void insertQuarter() {
        System.out.println("HasQuarter,已存在钱币,不用再投币了");
    }

    public void ejectQuarter() {
        System.out.println("HasQuarter,退币,进入NoQuarter");
        cumballMachine.setState(cumballMachine.getNoQuarter());
    }

    public void turnCrank() {
        System.out.println("HasQuarter,转轴,进入soldState");
        int in= new Random().nextInt(100);
        if (in % 3 == 1) {
            cumballMachine.setState(cumballMachine.getSoldState());
        } else {
            cumballMachine.setState(cumballMachine.getWinnerState());
        }
    }

    public void dispense() {
        System.out.println("HasQuarter,未经过转轴,不可发放糖果");
    }
}
public class WinnerState implements State {
    private CumballMachine cumballMachine;

    public WinnerState(CumballMachine cumballMachine) {
        this.cumballMachine = cumballMachine;
    }

    public void insertQuarter() {
        System.out.println("WinnerState,不允许投币");
    }

    public void ejectQuarter() {
        System.out.println("WinnerState,不允许退币");
    }

    public void turnCrank() {
        System.out.println("WinnerState,不允许转轴");
    }

    public void dispense() {
        System.out.println("恭喜中奖了");
        cumballMachine.releaseBall();
        if (cumballMachine.getCount() > 0) {
            cumballMachine.releaseBall();
            if (cumballMachine.getCount() == 0) {
                System.out.println("WinnerState,售罄,进入SoldOutState");
                cumballMachine.setState(cumballMachine.getSoldOutState());
            } else {
                System.out.println("WinnerState,进入NoQuarter");
                cumballMachine.setState(cumballMachine.getNoQuarter());
            }
        }
    }
}

c、环境类

/**
 * Desc:自动售货机
 * ------------------------------------
 * Author:XXXX
 * Date:2017/8/24
 * Time:11:32
 */
@Data
public class CumballMachine implements State{
    private State hasQuarter;
    private State noQuarter;
    private State soldState;
    private State soldOutState;
    private State winnerState;
    private State state;      // 售货机当前状态
    private int count;         // 售货机糖果数量

    public CumballMachine(int count) {
        hasQuarter = new HasQuarter(this);
        noQuarter = new NoQuarter(this);
        soldOutState = new SoldOutState(this);
        soldState = new SoldState(this);
        winnerState = new WinnerState(this);
        this.count = count;
        this.state = noQuarter;
    }

    public void releaseBall() {
        System.out.println("发放糖果");
        this.count--;
    }

    public void insertQuarter() {
        state.insertQuarter();
    }

    public void ejectQuarter() {
        state.ejectQuarter();
    }

    public void turnCrank() {
        state.turnCrank();
    }

    public void dispense() {
        state.dispense();
    }
}

d、测试类

public class Test {
    public static void main(String[] args) {
        CumballMachine cumballMachine = new CumballMachine(4);
        cumballMachine.insertQuarter();
        cumballMachine.turnCrank();
        cumballMachine.dispense();
    }
}

6、状态模式的扩展

简单状态模式与可切换状态的状态模式:

(1) 简单状态模式:简单状态模式是指状态都相互独立,状态之间无须进行转换的状态模式,这是最简单的一种状态模式。对于这种状态模式, 每个状态类都封装与状态相关的操作,而无须关心状态的切换,可以在客户端直接实例化状态类,然后将状态对象设置到环境类中。 如果是这种简单的状态模式,它遵循“开闭原则”,在客户端可以针对抽象状态类进行编程,而将具体状态类写到配置文件中,同时增加新的状态 类对原有系统也不造成任何影响。

(2) 可切换状态的状态模式:大多数的状态模式都是可以切换状态的状态模式,在实现状态切换时,在具体状态类内部需要调用环境类Context 的setState()方法进行状态的转换操作,在具体状态类中可以调用到环境类的方法,因此状态类与环境类之间通常还存在关联关系或者依赖关系 。通过在状态类中引用环境类的对象来回调环境类的setState()方法实现状态的切换。在这种可以切换状态的状态模式中,增加新的状态类可能需 要修改其他某些状态类甚至环境类的源代码,否则系统无法切换到新增状态。