设计模式——(13)状态模式

第十三章 状态模式

1.1 糖果机的状态

在现实世界中,有一台糖果机,可以糖果机上执行如下动作:

  • 投入一枚25分钱的硬币(机器上有按钮)
  • 退出一枚25分钱的硬币(机器上有按钮)
  • 转动曲柄以获取糖果(机器上有曲柄)
  • 糖果机释放糖果(糖果机在转动曲柄后,自动释放)
  • 重新为糖果机装填糖果

而糖果机的状态转换如下:

请添加图片描述

假定糖果机中有一定量的糖果,此时为 没有25分钱 的状态,当向糖果机投入25分钱后,糖果机进入有25分钱 的状态,在此状态下,可以按下退出硬币按钮,待退出硬币后,进入 没有25分钱 ,或者转动曲柄,进入售出糖果 的状态,然后机器自动发放糖果,发放糖果后,根据糖果机内的糖果数量选择进入糖果售罄或者是 没有25分钱的状态。

1.2 使用状态模式定义糖果机

定义糖果机的状态和接口:
请添加图片描述

因为我们可能在任意一种状态下,对糖果机执行动作,因此,状态接口实现了不同动作的接口。

实现糖果机 GumballMachine 的代码:

package headfirst.designpatterns.state.gumballstate;

public class GumballMachine {
    // 糖果机中有不同的状态属性,糖果机的当前状态可以在这些不同状态中切换。
    State soldOutState;
    State noQuarterState;
    State hasQuarterState;
    State soldState;

    // 糖果机的当前状态
    State state;
    // 糖果机中的糖果数量
    int count = 0;

    // 给定糖果数量,初始化糖果机。
    public GumballMachine(int numberGumballs) {
        soldOutState = new SoldOutState(this);
        noQuarterState = new NoQuarterState(this);
        hasQuarterState = new HasQuarterState(this);
        soldState = new SoldState(this);

        this.count = numberGumballs;
        if (numberGumballs > 0) {
            state = noQuarterState;
        } else {
            state = soldOutState;
        }
    }
    
    // 对糖果机中执行操作时,实际是对当前状态下的糖果机进行动作,因此调用当前状态下的对应动作。
    public void insertQuarter() {
        state.insertQuarter();
    }

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

    // 由于糖果机在转动曲柄后是自动释放糖果,因此,转动曲柄和释放糖果是先后顺序执行。
    public void turnCrank() {
        state.turnCrank();
        state.dispense();
    }

    void releaseBall() {
        System.out.println("A gumball comes rolling out the slot...");
        if (count > 0) {
            count = count - 1;
        }
    }

    int getCount() {
        return count;
    }

    void refill(int count) {
        this.count += count;
        System.out.println("The gumball machine was just refilled; its new count is: " + this.count);
        state.refill();
    }

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

    public State getState() {
        return state;
    }

    public State getSoldOutState() {
        return soldOutState;
    }

    public State getNoQuarterState() {
        return noQuarterState;
    }

    public State getHasQuarterState() {
        return hasQuarterState;
    }

    public State getSoldState() {
        return soldState;
    }

    public String toString() {
        StringBuffer result = new StringBuffer();
        result.append("\nMighty Gumball, Inc.");
        result.append("\nJava-enabled Standing Gumball Model #2004");
        result.append("\nInventory: " + count + " gumball");
        if (count != 1) {
            result.append("s");
        }
        result.append("\n");
        result.append("Machine is " + state + "\n");
        return result.toString();
    }
}

定义 State 接口:

package headfirst.designpatterns.state.gumballstate;

public interface State {

	 void insertQuarter();
	 void ejectQuarter();
	 void turnCrank();
	 void dispense();
	
	 void refill();
}

定义没有25分钱 的状态:

package headfirst.designpatterns.state.gumballstate;

public class NoQuarterState implements State {
    // 在当前状态执行相应的操作后,涉及对糖果机状态的改变,因此,依赖GumballMachine。
    GumballMachine gumballMachine;
 
    public NoQuarterState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
 
	public void insertQuarter() {
		System.out.println("You inserted a quarter");
		gumballMachine.setState(gumballMachine.getHasQuarterState());
	}
 
	public void ejectQuarter() {
		System.out.println("You haven't inserted a quarter");
	}
 
	public void turnCrank() {
		System.out.println("You turned, but there's no quarter");
	 }
 
	public void dispense() {
		System.out.println("You need to pay first");
	} 
	
	public void refill() { }
 
	public String toString() {
		return "waiting for quarter";
	}
}

定义有25分钱 的状态:

package headfirst.designpatterns.state.gumballstate;

public class HasQuarterState implements State {
	GumballMachine gumballMachine;
 
	public HasQuarterState(GumballMachine gumballMachine) {
		this.gumballMachine = gumballMachine;
	}


	public void insertQuarter() {
		System.out.println("You can't insert another quarter");
	}
 
	public void ejectQuarter() {
		System.out.println("Quarter returned");
		gumballMachine.setState(gumballMachine.getNoQuarterState());
	}
 
	public void turnCrank() {
		System.out.println("You turned...");
		gumballMachine.setState(gumballMachine.getSoldState());
	}

    public void dispense() {
        System.out.println("No gumball dispensed");
    }
    
    public void refill() { }
 
	public String toString() {
		return "waiting for turn of crank";
	}
}

定义售出糖果的状态:

package headfirst.designpatterns.state.gumballstate;

public class SoldState implements State {
 
    GumballMachine gumballMachine;
 
    public SoldState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
       
	public void insertQuarter() {
		System.out.println("Please wait, we're already giving you a gumball");
	}
 
	public void ejectQuarter() {
		System.out.println("Sorry, you already turned the crank");
	}
 
	public void turnCrank() {
		System.out.println("Turning twice doesn't get you another gumball!");
	}
 
	public void dispense() {
		gumballMachine.releaseBall();
		if (gumballMachine.getCount() > 0) {
			gumballMachine.setState(gumballMachine.getNoQuarterState());
		} else {
			System.out.println("Oops, out of gumballs!");
			gumballMachine.setState(gumballMachine.getSoldOutState());
		}
	}
	
	public void refill() { }
 
	public String toString() {
		return "dispensing a gumball";
	}
}

定义售罄糖果的状态:

package headfirst.designpatterns.state.gumballstate;

public class SoldOutState implements State {
    GumballMachine gumballMachine;
 
    public SoldOutState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
 
	public void insertQuarter() {
		System.out.println("You can't insert a quarter, the machine is sold out");
	}
 
	public void ejectQuarter() {
		System.out.println("You can't eject, you haven't inserted a quarter yet");
	}
 
	public void turnCrank() {
		System.out.println("You turned, but there are no gumballs");
	}
 
	public void dispense() {
		System.out.println("No gumball dispensed");
	}
	
	public void refill() { 
		gumballMachine.setState(gumballMachine.getNoQuarterState());
	}
 
	public String toString() {
		return "sold out";
	}
}

测试:

package headfirst.designpatterns.state.gumballstate;

public class GumballMachineTestDrive {

	public static void main(String[] args) {
		GumballMachine gumballMachine = new GumballMachine(2);

		System.out.println(gumballMachine);

		gumballMachine.insertQuarter();
		gumballMachine.turnCrank();

		System.out.println(gumballMachine);

		gumballMachine.insertQuarter();
		gumballMachine.turnCrank();
		gumballMachine.insertQuarter();
		gumballMachine.turnCrank();
		
		gumballMachine.refill(5);
		gumballMachine.insertQuarter();
		gumballMachine.turnCrank();

		System.out.println(gumballMachine);
	}
}

测试结果:

Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 2 gumballs
Machine is waiting for quarter

You inserted a quarter
You turned...
A gumball comes rolling out the slot...

Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 1 gumball
Machine is waiting for quarter

You inserted a quarter
You turned...
A gumball comes rolling out the slot...
Oops, out of gumballs!
You can't insert a quarter, the machine is sold out
You turned, but there are no gumballs
No gumball dispensed
The gumball machine was just refilled; its new count is: 5
You inserted a quarter
You turned...
A gumball comes rolling out the slot...

Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 4 gumballs
Machine is waiting for quarter

1.3 状态模式

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

这里的对象为糖果机,其状态改变时,操作糖果机会导致其有不同的行为。

状态模式将状态封装成独立的类,并将动作委托到代表当前状态的对象,行为随内部状态改变而改变。例如:糖果机在NoQuarterState和HasQuarterState两种状态时,投入 25分钱,会得到不同的行为。

可以忽略对象组合和个别对象之间的差异。

组合模式的类图如下图所示。

请添加图片描述

状态模式与策略方式很像,状态模式是将一群行为封装在状态对象中,context的行为随时可委托到那些状态对象中的一个。

参考

[1] Freeman E. Head First 设计模式[M] 中国电力出版社.
[2] 菜鸟教程.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值