策略模式 VS 形态模式

发布日期:2019-09-05 17:02:05 阅读数: 103次 来源:亚博手机app

亚博手机app-
					<p>外行为类设想模式中,形态模式和策略模式是亲兄弟,两者很是类似,我们先看看两者的通用类图,把两者放在一路比力一下,如图所示:</p>

<p><img src=

二者是不是很像,光看这个 UML 我们看不出什么眉目来,接下来我们连系例子,来对比一下二者之间的区别。下面的例子是《Head First 设想模式》中的例子。


策略模式

策略模式定义了算法族,别离封装起来,让他们之间能够互相替代,此模式让算法的变化独立于利用算法的客户。

某公司开辟了一个鸭子游戏,里面会呈现各类特点的鸭子:绿头鸭,红头鸭,橡皮鸭……用法式若何实现这些鸭子? 看到这个场景问题,很容易想到,先定义一个所有鸭子的超类Duck,把公共方式和属性封装进去。例如,鸭子城市泅水,鸭子都有各自的表面:

实例

public abstract class Duck {
    public void swim(){
        System.out.println("All duck can swim!");
    }
    public abstract void display();
    public void fly(){
        System.out.println("飞~~~");
    }
    public void quack(){
        System.out.println("呱呱呱~");
    }
}

可是很快,我们发觉这个超类的定义有问题。不是所有鸭子城市飞,不是所有鸭子都是呱呱叫(假设橡皮鸭是吱吱叫)。只需承继了这个超类,那所有的鸭子城市飞了,所有的鸭子都是呱呱叫了。

怎样办呢?

Solution 1

第一个想到的处理方式是:子类进行方式笼盖。很简单,不会飞的子类笼盖fly方式,重写不就行了?

可是,短处很较着,所有不会飞的子类岂不都是要笼盖,假设50种鸭子都不会飞,那重写的工作量和维护量得有多大?

Solution 2

好的,所以我们想到第二个方式:继续设想子笼统类,例如会飞不会叫的笼统子类FlyNoQuackDuck,会叫不会非的笼统子类QuackNoFlyDuck,不会叫不会飞的笼统子类NoQuackNoFlyDuck,又会飞又会叫的笼统子类FlyAndQuackDuck……

写着写着我们发觉这种方式也不可,太不矫捷,并且改变的部门越多,这种笼统子类得定义的越多。

Solution 3

那什么方式才好呢?我们思虑,之所以呈现上面的问题,是由于我们习惯性的总想用承继来实现改变的部门,现实我们能够将改变的部门抽离出来,用组合来实现。

这里用到了三个设想准绳:

  • 找出使用中可能需要变化之处,把他们独立出来。
  • 针对接口编程,而不是针对实现
  • 多用组合,罕用承继

使用第一个设想准绳,我们将改变的方式fly()和quack()独立出来,封装成两个行为类接口。然后按照分歧的需求,设想出实现接口的分歧行为类。

使用第二个和第三个设想准绳,我们在Duck类中组合两个成员变量的接口,在子类中动态的赋值。

全体的"类图"如下:

总结

这种处理方式很完满的处理了我们的问题,使用"策略模式"的思惟,将变化的部门抽离出来,组合进类中,按照分歧的子类,能够"set"分歧的行为子类进行,实现动态改变行为。

代码实现

两个行为接口类

实例

public interface FlyBehavior {
    public void fly();
}

public interface QuackBehavior {
    public void quack();
}

实现飞翔接口的分歧行为类

实例

public class FlyNoWay implements FlyBehavior{
    public void fly(){
        System.out.println("我不克不及飞……");
    }
}

public class FlyWithWings implements FlyBehavior{
    public void fly(){
        System.out.println("飞~~~");
    }
}

public class FlyWithRocket implements FlyBehavior{

    public void fly(){
        System.out.println("带上火箭筒,飞~~~");
    }
}

实现鸭叫的分歧行为类

实例

public class Quack implements QuackBehavior{
    public void quack(){
        System.out.println("呱呱呱~");
    }
}


public class Squeak implements QuackBehavior{
    public void quack(){
        System.out.println("吱吱吱~");
    }
}


public class MuteQuack implements QuackBehavior{
    public void quack(){
        System.out.println("我不会叫……");
    }
}

组合了实现接口的超类

实例

public abstract class Duck {
    protected FlyBehavior flyBehavior;
    protected QuackBehavior quackBehavior;

    public void swim(){
        System.out.println("All duck can swim!");
    }

    public abstract void display();

    /**
     * 动态改变飞翔行为
     */

    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    /**
     * 动态改变鸭叫行为
     */

    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }

    public void performFly(){
        flyBehavior.fly();
    }

    public void performQuack(){
        quackBehavior.quack();
    }
}

分歧的鸭子类

实例

/**
 * 绿头鸭
 */

public class MallarDuck extends Duck{

    public MallarDuck() {
        //可飞
        flyBehavior = new FlyWithWings();
        //呱呱叫
        quackBehavior = new Quack();
    }

    @Override
    public void display() {
        System.out.println("看着像绿头鸭");
    }

}

/**
 * 绿头鸭
 */

public class RedHeadDuck extends Duck{

    public RedHeadDuck() {
        //可飞
        flyBehavior = new FlyWithWings();
        //呱呱叫
        quackBehavior = new Quack();
    }

    @Override
    public void display() {
        System.out.println("看着像红头鸭");
    }

}

/**
 * 橡皮鸭
 */

public class RubberDuck extends Duck{

    public RubberDuck() {
        //不会飞
        flyBehavior = new FlyNoWay();
        //吱吱叫
        quackBehavior = new Squeak();
    }

    @Override
    public void display() {
        System.out.println("看着像橡皮鸭");
    }

}

形态模式

形态模式答应对象在内部形态改变时改变它的行为,对象看起来仿佛点窜了它的类

形态模式策略模式很类似,也是将类的"形态"封装了起来,在施行动作时进行主动的转换,从而实现,类在分歧形态下的统一动作显示出分歧成果。它与策略模式的区别在于,这种转换是"主动","无认识"的。

形态模式的类图如下

形态模式的类图与策略模式一模一样,区别在于它们的企图。策略模式会节制对象利用什么策略,而形态模式会主动改变形态。看完下面的案例该当就清晰了。

此刻有一个糖果机的需求摆在你面前,需要用Java实现。

我们阐发一下,糖果机的功能能够分为下图所示的四个动作和四个形态:

在分歧形态下,同样的动作成果纷歧样。例如,在"投了25分钱"的形态下"动弹曲柄",会售出糖果;而在"没有25分钱"的形态下"动弹曲柄"会提醒请先投币。

简单思虑后,我们写出如下的糖果机实现代码

实例

public class NoPatternGumballMachine{
    /*
     * 四个形态
     */

    /**没有硬币形态*/
    private final static int NO_QUARTER = 0;
    /**投币形态*/
    private final static int HAS_QUARTER = 1;
    /**出售糖果形态*/
    private final static int SOLD = 2;
    /**糖果售尽形态*/
    private final static int SOLD_OUT = 3;

    private int state = SOLD_OUT;
    private int candyCount = 0;

    public NoPatternGumballMachine(int count) {
        this.candyCount = count;
        if(candyCount > 0)
            state = NO_QUARTER;
    }

    /*
     * 四个动作
     */


    /**
     * 投币
     */

    public void insertQuarter() {
        if(NO_QUARTER == state){
            System.out.println("投币");
            state = HAS_QUARTER;
        }
        else if(HAS_QUARTER == state){
            System.out.println("请不要反复投币!");
            returnQuarter();
        }
        else if(SOLD == state){
            System.out.println("已投币,请期待糖果");
            returnQuarter();
        }else if(SOLD_OUT == state){
            System.out.println("糖果曾经售尽");
            returnQuarter();
        }
    }

    /**
     * 退币
     */

    public void ejectQuarter() {
        if(NO_QUARTER == state){
            System.out.println("没有硬币,无法弹出");
        }
        else if(HAS_QUARTER == state){
            returnQuarter();
            state = NO_QUARTER;
        }
        else if(SOLD == state){
            System.out.println("无法退币,正在发放糖果,请期待");
        }else if(SOLD_OUT == state){
            System.out.println("没有投币,无法退币");
        }
    }

    /**
     * 动弹出糖曲轴
     */

    public void turnCrank() {
        if(NO_QUARTER == state){
            System.out.println("请先投币");
        }
        else if(HAS_QUARTER == state){
            System.out.println("动弹曲轴,预备发糖");
            state = SOLD;
        }
        else if(SOLD == state){
            System.out.println("已按过曲轴,请期待");
        }else if(SOLD_OUT == state){
            System.out.println("糖果曾经售尽");
        }
    }

    /**
     * 发糖
     */

    public void dispense() {
        if(NO_QUARTER == state){
            System.out.println("没有投币,无法发放糖果");
        }
        else if(HAS_QUARTER == state){
            System.out.println("this method don't support");
        }
        else if(SOLD == state){
            if(candyCount > 0){
                System.out.println("分发一颗糖果");
                candyCount --;
                state = NO_QUARTER;
            }
            else{
                System.out.println("抱愧,糖果已售尽");
                state = SOLD_OUT;
            }
        }else if(SOLD_OUT == state){
            System.out.println("抱愧,糖果已售尽");
        }
    }

    /**
     * 退还硬币
     */

    protected void returnQuarter() {
        System.out.println("退币……");
    }

}

从代码里面能够看出,糖果机按照此刻分歧的形态,而使对应的动作呈现分歧的成果。这份代码曾经能够满足我们的根基需求,但稍微思虑一下,你会感觉这种实现代码似乎,功能太复杂了,扩展性很差,没有面向对象的气概。

假设因为新需求,要添加一种形态,那每个动作方式我们都需要点窜,都要从头添加一条else语句。而若是需求变动,某个形态下的动作需要点窜,我们也要同时改动四个方式。如许的工作将是繁琐而头大的。

怎样办? 六大设想准绳之一

找出使用中可能需要变化之处,把他们独立出来。

在糖果机中,形态就是不断在变化的部门,分歧的形态动作纷歧样。我们完全能够将其抽离出来

新的设想设法如下:

起首,我们定义一个State接口,在这个接口内,糖果机的每个动作都有一个对应的方式

然后为机械的每个形态实现形态类,这些类将担任在对应的形态下进行机械的行为

最初,我们要脱节旧的前提代码,取而代之的体例是,将动作委托到形态类

定义一个State接口

实例

public abstract class State {
    /**
     * 投币
     */

    public abstract void insertQuarter();

    /**
     * 退币
     */

    public abstract void ejectQuarter();

    /**
     * 动弹出糖曲轴
     */

    public abstract void turnCrank();

    /**
     * 发糖
     */

    public abstract void dispense();

    /**
     * 退还硬币
     */

    protected void returnQuarter() {
        System.out.println("退币……");
    }
}

为机械的每个形态实现形态类

实例

/**
 * 没有硬币的形态
 */

public class NoQuarterState extends State{
    GumballMachine gumballMachine;

    public NoQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    @Override
    public void insertQuarter() {
        System.out.println("你投入了一个硬币");
        //转换为有硬币形态
        gumballMachine.setState(gumballMachine.hasQuarterState);
    }

    @Override
    public void ejectQuarter() {
        System.out.println("没有硬币,无法弹出");
    }

    @Override
    public void turnCrank() {
        System.out.println("请先投币");
    }

    @Override
    public void dispense() {
        System.out.println("没有投币,无法发放糖果");
    }

}

/**
 * 投硬币的形态
 */

public class HasQuarterState extends State{
    GumballMachine gumballMachine;

    public HasQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    @Override
    public void insertQuarter() {
        System.out.println("请不要反复投币!");
        returnQuarter();
    }

    @Override
    public void ejectQuarter() {
        returnQuarter();
        gumballMachine.setState(gumballMachine.noQuarterState);
    }

    @Override
    public void turnCrank() {
        System.out.println("动弹曲轴,预备发糖");
        gumballMachine.setState(gumballMachine.soldState);
    }

    @Override
    public void dispense() {
        System.out.println("this method don't support");
    }

}

/**
 * 出售的形态
 */

public class SoldState extends State{
    GumballMachine gumballMachine;

    public SoldState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertQuarter() {
        System.out.println("已投币,请期待糖果");
        returnQuarter();
    }

    @Override
    public void ejectQuarter() {
        System.out.println("无法退币,正在发放糖果,请期待");
    }

    @Override
    public void turnCrank() {
        System.out.println("已按过曲轴,请期待");
    }

    @Override
    public void dispense() {
        int candyCount = gumballMachine.getCandyCount();
        if(candyCount > 0){
            System.

外行为类设想模式中,形态模式和策略模式是亲兄弟,两者很是类似,我们先看看两者的通用类图,把两者放在一路比力一下,如图所示:

二者是不是很像,光看这个 UML 我们看不出什么眉目来,接下来我们连系例子,来对比一下二者之间的区别。下面的例子是《Head First 设想模式》中的例子。


策略模式

策略模式定义了算法族,别离封装起来,让他们之间能够互相替代,此模式让算法的变化独立于利用算法的客户。

某公司开辟了一个鸭子游戏,里面会呈现各类特点的鸭子:绿头鸭,红头鸭,橡皮鸭……用法式若何实现这些鸭子? 看到这个场景问题,很容易想到,先定义一个所有鸭子的超类Duck,把公共方式和属性封装进去。例如,鸭子城市泅水,鸭子都有各自的表面:

实例

public abstract class Duck {
    public void swim(){
        System.out.println("All duck can swim!");
    }
    public abstract void display();
    public void fly(){
        System.out.println("飞~~~");
    }
    public void quack(){
        System.out.println("呱呱呱~");
    }
}

可是很快,我们发觉这个超类的定义有问题。不是所有鸭子城市飞,不是所有鸭子都是呱呱叫(假设橡皮鸭是吱吱叫)。只需承继了这个超类,那所有的鸭子城市飞了,所有的鸭子都是呱呱叫了。

怎样办呢?

Solution 1

第一个想到的处理方式是:子类进行方式笼盖。很简单,不会飞的子类笼盖fly方式,重写不就行了?

可是,短处很较着,所有不会飞的子类岂不都是要笼盖,假设50种鸭子都不会飞,那重写的工作量和维护量得有多大?

Solution 2

好的,所以我们想到第二个方式:继续设想子笼统类,例如会飞不会叫的笼统子类FlyNoQuackDuck,会叫不会非的笼统子类QuackNoFlyDuck,不会叫不会飞的笼统子类NoQuackNoFlyDuck,又会飞又会叫的笼统子类FlyAndQuackDuck……

写着写着我们发觉这种方式也不可,太不矫捷,并且改变的部门越多,这种笼统子类得定义的越多。

Solution 3

那什么方式才好呢?我们思虑,之所以呈现上面的问题,是由于我们习惯性的总想用承继来实现改变的部门,现实我们能够将改变的部门抽离出来,用组合来实现。

这里用到了三个设想准绳:

  • 找出使用中可能需要变化之处,把他们独立出来。
  • 针对接口编程,而不是针对实现
  • 多用组合,罕用承继

使用第一个设想准绳,我们将改变的方式fly()和quack()独立出来,封装成两个行为类接口。然后按照分歧的需求,设想出实现接口的分歧行为类。

使用第二个和第三个设想准绳,我们在Duck类中组合两个成员变量的接口,在子类中动态的赋值。

全体的"类图"如下:

总结

这种处理方式很完满的处理了我们的问题,使用"策略模式"的思惟,将变化的部门抽离出来,组合进类中,按照分歧的子类,能够"set"分歧的行为子类进行,实现动态改变行为。

代码实现

两个行为接口类

实例

public interface FlyBehavior {
    public void fly();
}

public interface QuackBehavior {
    public void quack();
}

实现飞翔接口的分歧行为类

实例

public class FlyNoWay implements FlyBehavior{
    public void fly(){
        System.out.println("我不克不及飞……");
    }
}

public class FlyWithWings implements FlyBehavior{
    public void fly(){
        System.out.println("飞~~~");
    }
}

public class FlyWithRocket implements FlyBehavior{

    public void fly(){
        System.out.println("带上火箭筒,飞~~~");
    }
}

实现鸭叫的分歧行为类

实例

public class Quack implements QuackBehavior{
    public void quack(){
        System.out.println("呱呱呱~");
    }
}


public class Squeak implements QuackBehavior{
    public void quack(){
        System.out.println("吱吱吱~");
    }
}


public class MuteQuack implements QuackBehavior{
    public void quack(){
        System.out.println("我不会叫……");
    }
}

组合了实现接口的超类

实例

public abstract class Duck {
    protected FlyBehavior flyBehavior;
    protected QuackBehavior quackBehavior;

    public void swim(){
        System.out.println("All duck can swim!");
    }

    public abstract void display();

    /**
     * 动态改变飞翔行为
     */

    public void setFlyBehavior(FlyBehavior flyBehavior) {
        this.flyBehavior = flyBehavior;
    }

    /**
     * 动态改变鸭叫行为
     */

    public void setQuackBehavior(QuackBehavior quackBehavior) {
        this.quackBehavior = quackBehavior;
    }

    public void performFly(){
        flyBehavior.fly();
    }

    public void performQuack(){
        quackBehavior.quack();
    }
}

分歧的鸭子类

实例

/**
 * 绿头鸭
 */

public class MallarDuck extends Duck{

    public MallarDuck() {
        //可飞
        flyBehavior = new FlyWithWings();
        //呱呱叫
        quackBehavior = new Quack();
    }

    @Override
    public void display() {
        System.out.println("看着像绿头鸭");
    }

}

/**
 * 绿头鸭
 */

public class RedHeadDuck extends Duck{

    public RedHeadDuck() {
        //可飞
        flyBehavior = new FlyWithWings();
        //呱呱叫
        quackBehavior = new Quack();
    }

    @Override
    public void display() {
        System.out.println("看着像红头鸭");
    }

}

/**
 * 橡皮鸭
 */

public class RubberDuck extends Duck{

    public RubberDuck() {
        //不会飞
        flyBehavior = new FlyNoWay();
        //吱吱叫
        quackBehavior = new Squeak();
    }

    @Override
    public void display() {
        System.out.println("看着像橡皮鸭");
    }

}

形态模式

形态模式答应对象在内部形态改变时改变它的行为,对象看起来仿佛点窜了它的类

形态模式策略模式很类似,也是将类的"形态"封装了起来,在施行动作时进行主动的转换,从而实现,类在分歧形态下的统一动作显示出分歧成果。它与策略模式的区别在于,这种转换是"主动","无认识"的。

形态模式的类图如下

形态模式的类图与策略模式一模一样,区别在于它们的企图。策略模式会节制对象利用什么策略,而形态模式会主动改变形态。看完下面的案例该当就清晰了。

此刻有一个糖果机的需求摆在你面前,需要用Java实现。

我们阐发一下,糖果机的功能能够分为下图所示的四个动作和四个形态:

在分歧形态下,同样的动作成果纷歧样。例如,在"投了25分钱"的形态下"动弹曲柄",会售出糖果;而在"没有25分钱"的形态下"动弹曲柄"会提醒请先投币。

简单思虑后,我们写出如下的糖果机实现代码

实例

public class NoPatternGumballMachine{
    /*
     * 四个形态
     */

    /**没有硬币形态*/
    private final static int NO_QUARTER = 0;
    /**投币形态*/
    private final static int HAS_QUARTER = 1;
    /**出售糖果形态*/
    private final static int SOLD = 2;
    /**糖果售尽形态*/
    private final static int SOLD_OUT = 3;

    private int state = SOLD_OUT;
    private int candyCount = 0;

    public NoPatternGumballMachine(int count) {
        this.candyCount = count;
        if(candyCount > 0)
            state = NO_QUARTER;
    }

    /*
     * 四个动作
     */


    /**
     * 投币
     */

    public void insertQuarter() {
        if(NO_QUARTER == state){
            System.out.println("投币");
            state = HAS_QUARTER;
        }
        else if(HAS_QUARTER == state){
            System.out.println("请不要反复投币!");
            returnQuarter();
        }
        else if(SOLD == state){
            System.out.println("已投币,请期待糖果");
            returnQuarter();
        }else if(SOLD_OUT == state){
            System.out.println("糖果曾经售尽");
            returnQuarter();
        }
    }

    /**
     * 退币
     */

    public void ejectQuarter() {
        if(NO_QUARTER == state){
            System.out.println("没有硬币,无法弹出");
        }
        else if(HAS_QUARTER == state){
            returnQuarter();
            state = NO_QUARTER;
        }
        else if(SOLD == state){
            System.out.println("无法退币,正在发放糖果,请期待");
        }else if(SOLD_OUT == state){
            System.out.println("没有投币,无法退币");
        }
    }

    /**
     * 动弹出糖曲轴
     */

    public void turnCrank() {
        if(NO_QUARTER == state){
            System.out.println("请先投币");
        }
        else if(HAS_QUARTER == state){
            System.out.println("动弹曲轴,预备发糖");
            state = SOLD;
        }
        else if(SOLD == state){
            System.out.println("已按过曲轴,请期待");
        }else if(SOLD_OUT == state){
            System.out.println("糖果曾经售尽");
        }
    }

    /**
     * 发糖
     */

    public void dispense() {
        if(NO_QUARTER == state){
            System.out.println("没有投币,无法发放糖果");
        }
        else if(HAS_QUARTER == state){
            System.out.println("this method don't support");
        }
        else if(SOLD == state){
            if(candyCount > 0){
                System.out.println("分发一颗糖果");
                candyCount --;
                state = NO_QUARTER;
            }
            else{
                System.out.println("抱愧,糖果已售尽");
                state = SOLD_OUT;
            }
        }else if(SOLD_OUT == state){
            System.out.println("抱愧,糖果已售尽");
        }
    }

    /**
     * 退还硬币
     */

    protected void returnQuarter() {
        System.out.println("退币……");
    }

}

从代码里面能够看出,糖果机按照此刻分歧的形态,而使对应的动作呈现分歧的成果。这份代码曾经能够满足我们的根基需求,但稍微思虑一下,你会感觉这种实现代码似乎,功能太复杂了,扩展性很差,没有面向对象的气概。

假设因为新需求,要添加一种形态,那每个动作方式我们都需要点窜,都要从头添加一条else语句。而若是需求变动,某个形态下的动作需要点窜,我们也要同时改动四个方式。如许的工作将是繁琐而头大的。

怎样办? 六大设想准绳之一

找出使用中可能需要变化之处,把他们独立出来。

在糖果机中,形态就是不断在变化的部门,分歧的形态动作纷歧样。我们完全能够将其抽离出来

新的设想设法如下:

起首,我们定义一个State接口,在这个接口内,糖果机的每个动作都有一个对应的方式

然后为机械的每个形态实现形态类,这些类将担任在对应的形态下进行机械的行为

最初,我们要脱节旧的前提代码,取而代之的体例是,将动作委托到形态类

定义一个State接口

实例

public abstract class State {
    /**
     * 投币
     */

    public abstract void insertQuarter();

    /**
     * 退币
     */

    public abstract void ejectQuarter();

    /**
     * 动弹出糖曲轴
     */

    public abstract void turnCrank();

    /**
     * 发糖
     */

    public abstract void dispense();

    /**
     * 退还硬币
     */

    protected void returnQuarter() {
        System.out.println("退币……");
    }
}

为机械的每个形态实现形态类

实例

/**
 * 没有硬币的形态
 */

public class NoQuarterState extends State{
    GumballMachine gumballMachine;

    public NoQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    @Override
    public void insertQuarter() {
        System.out.println("你投入了一个硬币");
        //转换为有硬币形态
        gumballMachine.setState(gumballMachine.hasQuarterState);
    }

    @Override
    public void ejectQuarter() {
        System.out.println("没有硬币,无法弹出");
    }

    @Override
    public void turnCrank() {
        System.out.println("请先投币");
    }

    @Override
    public void dispense() {
        System.out.println("没有投币,无法发放糖果");
    }

}

/**
 * 投硬币的形态
 */

public class HasQuarterState extends State{
    GumballMachine gumballMachine;

    public HasQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
    @Override
    public void insertQuarter() {
        System.out.println("请不要反复投币!");
        returnQuarter();
    }

    @Override
    public void ejectQuarter() {
        returnQuarter();
        gumballMachine.setState(gumballMachine.noQuarterState);
    }

    @Override
    public void turnCrank() {
        System.out.println("动弹曲轴,预备发糖");
        gumballMachine.setState(gumballMachine.soldState);
    }

    @Override
    public void dispense() {
        System.out.println("this method don't support");
    }

}

/**
 * 出售的形态
 */

public class SoldState extends State{
    GumballMachine gumballMachine;

    public SoldState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }

    @Override
    public void insertQuarter() {
        System.out.println("已投币,请期待糖果");
        returnQuarter();
    }

    @Override
    public void ejectQuarter() {
        System.out.println("无法退币,正在发放糖果,请期待");
    }

    @Override
    public void turnCrank() {
        System.out.println("已按过曲轴,请期待");
    }

    @Override
    public void dispense() {
        int candyCount = gumballMachine.getCandyCount();
        if(candyCount > 0){
            System.