java 開發模式之十二 : 狀態模式

原理或定義

當一個對象的內在狀態改變時允許改變其行爲,這個對象看起來像是改變了其類。狀態模式中的行爲是由狀態來決定的,不同的狀態對應了不同的行

結構

環境類Context: 它定義了客戶程序需要的接口並維護一個具體狀態角色的實例,將與狀態相關的操作委託給當前的Concrete State對象來處
抽象狀態類State: 定義一個接口以封裝與Context的一個特定狀態相關的行爲;
具體狀態類ConcreteState: 每一子類實現一個與Context的一個狀態相關的行爲;

類圖

案例與代碼

本模式使用一個糖果機項目來做示例

智能糖果機,用Java軟件控制糖果機:
待機
投入一元硬幣
轉動把手
滑落一顆糖果
待機(根據機器內糖果庫存情況,是否提示售罄)


傳統實現:

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;
		}

	}
}
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();
	}
}

加入遊戲元素:有10%的概率可以拿到2粒糖果。


以上的設計會違反開閉原則,並且對狀態的維護麻煩。


開閉原則:對擴展開放,對修改原有的代碼關閉。


狀態模式的設計方案:


類圖:


狀態接口:

public interface State {
	public void insertCoin();
	public void returnCoin();
	public void turnCrank();
	public void dispense();
	public void printstate();
}


狀態族類:

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

	@Override
	public void insertCoin() {
		// TODO Auto-generated method stub
		System.out
		.println("you have inserted a coin,next,please turn crank!");
		mCandyMachine.setState(mCandyMachine.mHasCoin);
	}

	@Override
	public void returnCoin() {
		// TODO Auto-generated method stub
		System.out.println("you haven't inserted a coin yet!");
		
	}

	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out.println("you turned,but you haven't inserted a coin!");
		
	}

	@Override
	public void dispense() {
		// TODO Auto-generated method stub

	}

	@Override
	public void printstate() {
		// TODO Auto-generated method stub
		System.out.println("***OnReadyState***");
		
	}

}
public class SoldOutState implements State {


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


	@Override
	public void insertCoin() {
		// TODO Auto-generated method stub
		System.out.println("you can't insert coin,the machine sold out!");
		
	}


	@Override
	public void returnCoin() {
		// TODO Auto-generated method stub
		System.out
		.println("you can't return,you haven't inserted a coin yet!");


	}


	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out.println("you turned,but there are no candies!");
		
	}


	@Override
	public void dispense() {
		// TODO Auto-generated method stub


	}


	@Override
	public void printstate() {
		// TODO Auto-generated method stub
		System.out.println("***SoldOutState***");
	
	}


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


	@Override
	public void insertCoin() {
		// TODO Auto-generated method stub
		System.out.println("please wait!we are giving you a candy!");


	}


	@Override
	public void returnCoin() {
		// TODO Auto-generated method stub
		System.out.println("you haven't inserted a coin yet!");
		
	}


	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out
		.println("we are giving you a candy,turning another get nothing,!");


	}


	@Override
	public void dispense() {
		// TODO Auto-generated method stub
		
		mCandyMachine.releaseCandy();
		if (mCandyMachine.getCount() > 0) {
			mCandyMachine.setState(mCandyMachine.mOnReadyState);
		} else {
			System.out.println("Oo,out of candies");
			mCandyMachine.setState(mCandyMachine.mSoldOutState);
		}


	
	
	}


	@Override
	public void printstate() {
		// TODO Auto-generated method stub
		System.out.println("***SoldState***");
		
	}


}
public class WinnerState implements State {


	private CandyMachine mCandyMachine;


	public WinnerState(CandyMachine mCandyMachine) {
		this.mCandyMachine = mCandyMachine;
	}


	@Override
	public void insertCoin() {
		// TODO Auto-generated method stub
		System.out.println("please wait!we are giving you a candy!");


	}


	@Override
	public void returnCoin() {
		// TODO Auto-generated method stub
		System.out.println("you haven't inserted a coin yet!");


	}


	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out
				.println("we are giving you a candy,turning another get nothing,!");


	}


	@Override
	public void dispense() {
		// TODO Auto-generated method stub


		
		mCandyMachine.releaseCandy();
		if (mCandyMachine.getCount() == 0) {
			mCandyMachine.setState(mCandyMachine.mSoldOutState);
		} else {
			System.out.println("you are a winner!you get another candy!");
			mCandyMachine.releaseCandy();
			if (mCandyMachine.getCount() > 0) {
				mCandyMachine.setState(mCandyMachine.mOnReadyState);
			} else {
				System.out.println("Oo,out of candies");
				mCandyMachine.setState(mCandyMachine.mSoldOutState);
			}
		}


	}


	@Override
	public void printstate() {
		// TODO Auto-generated method stub
		System.out.println("***WinnerState***");


	}


}
public class HasCoin implements State {
	private CandyMachine mCandyMachine;


	public HasCoin(CandyMachine mCandyMachine) {
		this.mCandyMachine = mCandyMachine;
	}


	@Override
	public void insertCoin() {
		// TODO Auto-generated method stub
		System.out.println("you can't insert another coin!");


	}


	@Override
	public void returnCoin() {
		// TODO Auto-generated method stub
		System.out.println("coin return!");
		mCandyMachine.setState(mCandyMachine.mOnReadyState);
	}


	@Override
	public void turnCrank() {
		// TODO Auto-generated method stub
		System.out.println("crank turn...!");
		Random ranwinner=new Random();
		int winner=ranwinner.nextInt(10);
		if(winner==0)
		{
			mCandyMachine.setState(mCandyMachine.mWinnerState);


		}else
		{
			mCandyMachine.setState(mCandyMachine.mSoldState);


		}
		
	}


	@Override
	public void dispense() {
	}


	@Override
	public void printstate() {
		// TODO Auto-generated method stub
		System.out.println("***HasCoin***");


	}


}

糖果機類:

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() {

		// TODO Auto-generated method stub
		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 MainTest {
	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();
	}
}

狀態模式:能根據內部狀態的變化,改變對象的行爲,看起來好像修改了類。不同的狀態對應不同的類文件,增加了系統文件個數。


使用場景

1. 一個對象的行爲取決於他的狀態,並且它必須在運行時根據狀態改變它的行爲;
2.一個操作中含有龐大的多分支結構,並且這些分支決定於對象的狀

優缺點

主要優點有:

1.狀態模式將不同狀態所對應的行爲彼此分隔開來,降低程序的耦合,從而在新增或修改狀態時,可以避免程序互相影響。

2.狀態模式將狀態的邏輯處理變化交由上下文對象Context管理,便於客戶端的調用

 

缺點主要有

不同的狀態對應不同的類文件,增加了系統文件個數,不便於維護管理

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章