状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。状态模式将状态封装成独立的类,并将动作委托到代表当前状态的对象,这样类的行为就随着状态的改变而变化。
让我们通过类图来进一步理解状态模式。
(2-1)
状态模式将一群行为封装到状态对象中,Context通过委托让具体的状态对象执行操作。如果Context中的状态发送改变,Context中的行为也会发生改变。而且Context的客户端不用关心状态对象,也不用关心Context中的状态何时改变。
在这里引用headfirst中的例子阐述怎样用代码实现状态模式。
图(3-1)是一个糖果机器的状态图,从图中我们可以了解到糖果机总共有投币、退币、摇杆、出糖果、放糖果五个操作,有币、无币、销售糖果、售罄四种状态。
(3-1)
参考上文中的状态模式定义和类图,我们抽象出了糖果机的四种状态和五种行为,接下来我们需要将糖果机的行为封装到状态对象中,让糖果机通过委托的方式调用不同的状态执行对应的操作。
package cn.lzz.state;
/**
* 所有状态对应的统一接口
* @author lizhizhou
*
*/
public interface State {
/**
* 投币
*/
public void insertQuarter();
/**
* 退币
*/
public void ejectQuarter();
/**
* 摇动摇杆
*/
public void turnGrank();
/**
* 出糖果
*/
public void dispence();
}
package cn.lzz.state;
import java.util.Random;
/**
* 有币状态
* @author lizhizhou
*
*/
public class HasQuarterState implements State {
private GumballMachine gumballMachine;
private Random random=new Random();
public HasQuarterState(GumballMachine gumballMachine){
this.gumballMachine=gumballMachine;
}
@Override
public void insertQuarter() {
// TODO Auto-generated method stub
System.out.println("You can't insert another quarter");
}
@Override
public void ejectQuarter() {
// TODO Auto-generated method stub
System.out.println("Quarter retured");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
@Override
public void turnGrank() {
// TODO Auto-generated method stub
System.out.println("You turn....");
gumballMachine.setState(gumballMachine.getSoldState());
}
@Override
public void dispence() {
// TODO Auto-generated method stub
System.out.println("No gumballs dispensed");
}
}
package cn.lzz.state;
/**
* 无币状态
* @author lizhizhou
*
*/
public class NoQuarterState implements State {
private GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine){
this.gumballMachine=gumballMachine;
}
@Override
public void insertQuarter() {
// TODO Auto-generated method stub
System.out.println("You inserted a quarter.");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
@Override
public void ejectQuarter() {
// TODO Auto-generated method stub
System.out.println("You haven't insertered a quarter.");
}
@Override
public void turnGrank() {
// TODO Auto-generated method stub
System.out.println("You turned,but there is no quarter.");
}
@Override
public void dispence() {
// TODO Auto-generated method stub
System.out.println("You need to pay first.");
}
}
package cn.lzz.state;
/**
* 售罄状态
* @author lizhizhou
*
*/
public class SoldOutState implements State{
private GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine){
this.gumballMachine=gumballMachine;
}
@Override
public void insertQuarter() {
// TODO Auto-generated method stub
System.out.println("Sorry,There isn't any gumball.");
}
@Override
public void ejectQuarter() {
// TODO Auto-generated method stub
System.out.println("There is no any quarter.");
}
@Override
public void turnGrank() {
// TODO Auto-generated method stub
System.out.println("Pleans,Don't turn grank.");
}
@Override
public void dispence() {
// TODO Auto-generated method stub
System.out.println("Sorry,There isn't any gumball.");
}
}
package cn.lzz.state;
/**
* 销售状态
* @author lizhizhou
*
*/
public class SoldState implements State {
private GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine){
this.gumballMachine=gumballMachine;
}
@Override
public void insertQuarter() {
// TODO Auto-generated method stub
}
@Override
public void ejectQuarter() {
// TODO Auto-generated method stub
}
@Override
public void turnGrank() {
// TODO Auto-generated method stub
}
@Override
public void dispence() {
// TODO Auto-generated method stub
gumballMachine.releaseBall();
if(gumballMachine.getCount()>0){
gumballMachine.setState(gumballMachine.getNoQuarterState());
}else{
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
package cn.lzz.state;
/**
* 糖果机
* @author lizhizhou
*
*/
public class GumballMachine {
//售罄
private State soldOutState;
//没有硬币
private State noQuarterState;
//有硬币
private State hasQuarterState;
//销售状态
private State soldState;
private State state=soldOutState;
private int count=0;
/**
* 初始化糖果机
* @param numbersGumball
*/
public GumballMachine(int numbersGumball){
this.soldOutState=new SoldOutState(this);
this.noQuarterState=new NoQuarterState(this);
this.hasQuarterState=new HasQuarterState(this);
this.soldState=new SoldState(this);
this.count=numbersGumball;
if(numbersGumball>0){
this.state=this.noQuarterState;
}
}
/**
* 投币
*/
public void insertQuarter(){
state.insertQuarter();
}
/**
* 退币
*/
public void ejectQuarter(){
state.ejectQuarter();
}
/**
* 转动摇杆
*/
public void turnGrank(){
state.turnGrank();
state.dispence();
}
/**
* 出糖果
*/
public void releaseBall(){
System.out.println("A gumball comes rolling out the solt.....");
if(count>0){
count=count-1;
}
}
/**
* 放入糖果
* @param count
*/
public void refill(int count){
if(count>0){
this.count+=count;
this.state=this.noQuarterState;
}
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public State getSoldOutState() {
return soldOutState;
}
public void setSoldOutState(State soldOutState) {
this.soldOutState = soldOutState;
}
public State getNoQuarterState() {
return noQuarterState;
}
public void setNoQuarterState(State noQuarterState) {
this.noQuarterState = noQuarterState;
}
public State getHasQuarterState() {
return hasQuarterState;
}
public void setHasQuarterState(State hasQuarterState) {
this.hasQuarterState = hasQuarterState;
}
public State getSoldState() {
return soldState;
}
public void setSoldState(State soldState) {
this.soldState = soldState;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public State getWinnerState() {
return winnerState;
}
public void setWinnerState(State winnerState) {
this.winnerState = winnerState;
}
@Override
public String toString() {
if(this.state==this.noQuarterState){
return "GumballMachine is wating for quarter.";
}else if(this.state==this.hasQuarterState){
return "GumballMachine has quarter.";
}else if(this.state==this.soldOutState){
return "GumballMachine has been soldOut.";
}else if(this.state==this.soldState){
return "GumballMachine is solding gumball.";
}else{
return "Hello";
}
}
}
package cn.lzz.state;
/**
* 测试代码
* @author lizhizhou
*
*/
public class GumballMachineTestDrive {
public static void main(String[] args) {
GumballMachine gumballMachine=new GumballMachine(10);
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnGrank();
System.out.println(gumballMachine);
gumballMachine.insertQuarter();
gumballMachine.turnGrank();
gumballMachine.insertQuarter();
gumballMachine.turnGrank();
System.out.println(gumballMachine);
}
}
GumballMachine is wating for quarter.
You inserted a quarter.
You turn....
A gumball comes rolling out the solt.....
GumballMachine is wating for quarter.
You inserted a quarter.
You turn....
A gumball comes rolling out the solt.....
You inserted a quarter.
You turn....
A gumball comes rolling out the solt.....
GumballMachine is wating for quarter.