设计模式之状态模式

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


有一个糖果机,它的状态图是这样的:



我们来实现糖果机:


public class GumballMachine {
	//四个状态
	final static int SOLD_OUT=0;
	final static int NO_QUARTER=1;
	final static int HAS_QUARTER=2;
	final static int SOLD=3;
	
	int state=SOLD_OUT;//跟踪当前状态,初始为 售罄
	int count=0;//追踪机器内的糖果数量
	
	public GumballMachine(int count){
		this.count=count;
		if(count>0)
			state=NO_QUARTER;//如果库存不为零,机器进入 没有25分钱状态
	}
	
	public void insertQuarter(){
		if(state==HAS_QUARTER)
			System.out.println("You cannot insert another quarter.");
		else if (state==NO_QUARTER) {
			state=HAS_QUARTER;
			System.out.println("You inserted a quarter");
		}else if (state==SOLD_OUT) {
			System.out.println("You cannont insert a quarter,the machine is sold out.");
		}else if(state==SOLD){
			System.out.println("Please wait,we're already giving you a gumball.");
		}
	}
	
	public void ejectQuarter(){
		if(state==HAS_QUARTER){
			System.out.println("Quarter returned.");
			state=NO_QUARTER;
		}else if (state==NO_QUARTER) {
			System.out.println("You haven't insert a quarter.");
		}else if (state==SOLD) {
			System.out.println("Sorry,you already turned the crank.");
		}else if (state==SOLD_OUT) {
			System.out.println("You cannot eject,you haven't insert a quarter yet.");
		}
	}
	
	public void turnCrank(){
		if(state==SOLD)
			System.out.println("Turning twice doesn't get you another gumball.");
		else if (state==NO_QUARTER) {
			System.out.println("You turned but there is no quarter.");
		}else if (state==SOLD_OUT) {
			System.out.println("You turned,but there is no gumball.");
		}else if (state==HAS_QUARTER) {
			System.out.println("You turned...");
			state=SOLD;
			dispense();
		}
	}
	
	public void dispense(){
		if(state==SOLD){
			System.out.println("A gumball comes rolling out the slot.");
			count=count-1;
			if(count==0){
				System.out.println("Oops,out of gumballs.");
				state=SOLD_OUT;
			}else {
				state=NO_QUARTER;
			}
		}else if (state==NO_QUARTER) {
			System.out.println("You need to pay first");
		}else if(state==SOLD_OUT){
			System.out.println("No gumballs dispensed");
		}else if (state==HAS_QUARTER) {
			System.out.println("No gumball dispensed");
		}
	}
	
	//其他方法

}

然后糖果公司有变更请求了:当曲柄被转动时,有10%几率掉下来两个糖果。

这样一来,以上的版本就不再适用了。

我们的计划是这样的:不再维护现有代码,重写他以便于将状态对象封装在各自的类,然后在动作发生时委托给当前状态。

首先,定义一个State接口,有4个方法对应4个动作

然后为每个状态实现状态类

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

	@Override
	public void insertQuarter() {
		// TODO Auto-generated method stub
		System.out.println("You insert a quarter");
		gumballMachine.setState(gumballMachine.getHasQuarterState());
	}

	@Override
	public void ejectQuarter() {
		// TODO Auto-generated method stub
		System.out.println("You haven't insert a quarter");
	}

	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out.println("You turned,but there's no quarter");
	}

	@Override
	public void dispense() {
		// TODO Auto-generated method stub
		System.out.println("You need to pay first");
	}

}

……


糖果机类:

public class GumballMachine {
	//四个状态
	 State soldOutState;
	 State noQuarterState;
	 State hasQuarterState;
	 State soldState;
	
	State state=soldOutState;//跟踪当前状态,初始为 售罄
	int count=0;//追踪机器内的糖果数量
	
	public GumballMachine(int count){
		soldOutState=new SoldOutState(this);
		noQuarterState=new NoQuarterState(this);
		hasQuarterState=new HasQuarterState(this);
		soldState=new SoldState(this);
		this.count=count;
		if(count>0)
			state=noQuarterState;//如果库存不为零,机器进入 没有25分钱状态
	}
	
	public void insertQuarter(){
		state.insertQuarter();
	}
	
	public void ejectQuarter(){
		state.ejectQuarter();
	}
	
	public void turnCrank(){
		state.turnCrank();
		state.dispense();
	}
	
	void setState(State state){
		this.state=state;
	}
	
	void releaseBall(){
		System.out.println("A gumball comes rolling out the slot...");
		if(count!=0)
			count=count-1;
	}
	
	//其他方法,getter
	

}


解决十次抽中一次的游戏:

首先在GumballMachine类中加入winnerState的状态然后初始化

在实现WinnerState本身

public class WinnerState implements State{
	//实例变量和构造器
	//insertQuarter错误信息
	//ejectQuarter错误信息
	//turnCrank错误信息
	


	@Override
	public void dispense() {
		// TODO Auto-generated method stub
		System.out.println("You are a winner!");
		gumballMachine=releaseBall();
		if(gumballMachine.getCount()==0)
			gumballMachine.setState(gumballMachine.getSoldOutState());
		else {
			gumballMachine.releaseBall();
			if(gumballMachine.getCount()>0)
				gumballMachine.setState(gumballMachine.getNoQuarterState());
			else {
				System.out.println("Oops,out of gumballs!");
				gumballMachine.setState(gumballMachine.getSoldOutState());
			}
		}
	}

在HasQuarterState中加入这个变化

public class HasQuarterState implements State{
	
	Random randomWinner=new Random(System.currentTimeMillis());
	GumballMachine gumballMachine;
	
	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 returned");
		gumballMachine.setState(gumballMachine.getNoQuarterState());
	}

	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out.println("YOu turned...");
		int winner=randomWinner.nextInt(10);
		if(winner==0 && gumballMachine.getCount()>1){
			gumballMachine.setState(gumballMachine.getWinnerState());
		}else {
			gumballMachine.setState(gumballMachine.getSoldState());
		}
	}

	@Override
	public void dispense() {
		// TODO Auto-generated method stub
		System.out.println("No gumball dispensed");
	}

}

OK 大功告成!


我发现状态模式和策略模式结构上很像,但是他们的意图不一样。策略是外部决定采取何种策略,状态是内部决定他们的状态变迁,外界只关心接口。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值