设计模式12-状态模式

647 阅读3分钟

1.场景问题解决

1.1 场景描述

糖果售卖机,状态有售完0,待机1,已投币2,给糖果3.

1.2 OO设计

  • 糖果售卖机
public class CandyMachine {

	final static int SoldOutState = 0;
	final static int OnReadyState = 1;
	final static int HasCoin = 2;
	final static int SoldState = 3;

	private int state = SoldOutState;
	private int count = 0;

	public CandyMachine(int count) {
		this.count = count;
		if (count > 0) {
			state = OnReadyState;
		}
	}

	public void insertCoin() {
		switch (state) {
		case SoldOutState:
			System.out.println("you can't insert coin,the machine sold out!");
			break;
		case OnReadyState:
			state = HasCoin;
			System.out.println("you have inserted a coin,next,please turn crank!");
			break;
		case HasCoin:
			System.out.println("you can't insert another coin!");

			break;
		case SoldState:
			System.out.println("please wait!we are giving you a candy!");
			break;
		}

	}

	public void returnCoin() {
		switch (state) {
		case SoldOutState:
			System.out.println("you can't return,you haven't inserted a coin yet!");
			break;
		case OnReadyState:
			System.out.println("you haven't inserted a coin yet!");
			break;
		case HasCoin:
			System.out.println("coin return!");
			state = OnReadyState;
			break;
		case SoldState:
			System.out.println("sorry,you already have turned the crank!");
			break;
		}

	}

	public void turnCrank() {
		switch (state) {
		case SoldOutState:
			System.out.println("you turned,but there are no candies!");
			break;
		case OnReadyState:
			System.out.println("you turned,but you haven't inserted a coin!");
			break;
		case HasCoin:
			System.out.println("crank turn...!");
			state = SoldState;
			dispense();
			break;
		case SoldState:
			System.out.println("we are giving you a candy,turning another get nothing,!");
			break;
		}

	}

	private void dispense() {
		count = count - 1;
		System.out.println("a candy rolling out!");
		if (count > 0) {
			state = OnReadyState;
		} else {
			System.out.println("Oo,out of candies");
			state = SoldOutState;
		}
	}

	public void printstate() {
		switch (state) {
		case SoldOutState:
			System.out.println("***SoldOutState***");
			break;
		case OnReadyState:
			System.out.println("***OnReadyState***");
			break;
		case HasCoin:
			System.out.println("***HasCoin***");
			break;
		case SoldState:
			System.out.println("***SoldState***");
			break;
		}
	}
}

  • MainTest 测试类
public class MainTest {
	public static void main(String[] args) {
		CandyMachine mCandyMachine=new CandyMachine(1);
		
		mCandyMachine.printstate();
		
		mCandyMachine.insertCoin();
		mCandyMachine.printstate();
		
		mCandyMachine.turnCrank();
		
		mCandyMachine.printstate();
		
		mCandyMachine.insertCoin();
		mCandyMachine.printstate();
		
		mCandyMachine.turnCrank();
		
		mCandyMachine.printstate();
	}
}

1.3 需求变动

加入游戏元素:有10%的概率可以拿到2粒糖果,会多了一个状态"中奖".

1.4 带来问题

加入一个状态后,状态的组合会增加许多,并且如果修改会修改之前的逻辑,修改代码较多.

2.用设计模式改进

状态改变但是行为不改变,所有可以把状态封装为对象,状态中封装了动作/行为.

2.1 分析

2.2 重新设计

12状态模式-1类图.png

2.3 源码

  • interface State
public interface State {
	//插入硬币
	public void insertCoin();
	//返回硬币
	public void returnCoin();
	//转动曲柄
	public void turnCrank();
	//分发糖果
	public void dispense();
	//打印状态
	public void printstate();
}

  • SoldOutState、HasCoin、OnReadyState、SoldState、 WinnerState 各状态实现State接口

public class SoldOutState implements State {
	private CandyMachine mCandyMachine;
	public SoldOutState(CandyMachine mCandyMachine)
	{
		this.mCandyMachine=mCandyMachine;
	}

	@Override
	public void insertCoin() {
		System.out.println("you can't insert coin,the machine sold out!");
	}

	@Override
	public void returnCoin() {
		System.out.println("you can't return,you haven't inserted a coin yet!");
	}

	@Override
	public void turnCrank() {
		System.out.println("you turned,but there are no candies!");
	}

	@Override
	public void dispense() {
	}

	@Override
	public void printstate() {
		System.out.println("***SoldOutState***");
	}
}
  • CandyMachine糖果机

public class CandyMachine {
	State mSoldOutState;
	State mOnReadyState;
	State mHasCoin;
	State mSoldState;
	State mWinnerState;
	private State state;
	private int count = 0;

	public CandyMachine(int count) {
		this.count = count;
		mSoldOutState = new SoldOutState(this);
		mOnReadyState = new OnReadyState(this);
		mHasCoin = new HasCoin(this);
		mSoldState = new SoldState(this);
		mWinnerState = new WinnerState(this);
		if (count > 0) {
			state = mOnReadyState;
		} else {
			state = mSoldOutState;
		}
	}

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

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

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

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

	void releaseCandy() {
		if (count > 0) {
			count = count - 1;
			System.out.println("a candy rolling out!");
		}
	}

	public int getCount() {
		return count;
	}

	public void printstate() {
		state.printstate();
	}
}
  • 测试类

public class StateTest {
	public static void main(String[] args) {
		CandyMachine mCandyMachine = new CandyMachine(6);

		mCandyMachine.printstate();

		mCandyMachine.insertCoin();
		mCandyMachine.printstate();

		mCandyMachine.turnCrank();

		mCandyMachine.printstate();

		mCandyMachine.insertCoin();
		mCandyMachine.printstate();

		mCandyMachine.turnCrank();

		mCandyMachine.printstate();
	}
}

3.设计模式总结

3.1 定义

状态模式能根据内部状态的变化,改变对象的行为,看起来好像修改了类

3.2 分析思路

状态是可变的,但是行为是固定的.
所以将状态定义为接口可变,接口中有行为是固定的,然后各种具体状态实现该状态接口,在各状态对象中处理各种行为是否可行.
状态对象中对修改的关闭,对功能的扩展.

4. 设计模式使用场景及注意

策略模式、状态模式和模板模式各自的含义
策略模式一般情况下可以作为状态模式的基础
模板模式与状态模式的差异

5.参考文章

内容总计于HeadFirst设计模式及相关视频