一柄错、狀態(tài)模式
能根據(jù)內(nèi)部狀態(tài)的變化埃碱,改變對(duì)象的行為嚎尤,看起來好像修改了類
二荔仁、示例
智能糖果機(jī):需要設(shè)計(jì)一款自助購買的糖果機(jī),糖果機(jī)的狀態(tài)有
- 準(zhǔn)備使用(接下來可投入硬幣)
- 投入硬幣(接下來可搖動(dòng)把手或者退出硬幣)
- 售出糖果(接下來可恢復(fù)使用或者售罄)
- 售罄狀態(tài)
使用傳統(tǒng)的面向?qū)ο竽J脚灯唬恍瓒x一個(gè)糖果機(jī)的對(duì)象咕晋,內(nèi)部根據(jù)不同的狀態(tài)進(jìn)行不同的操作處理
/**
* 面向?qū)ο竽J剑枪麢C(jī)
*/
public class CandyMachine {
final static int SoldOutState = 0; // 售罄狀態(tài)
final static int OnReadyState = 1; // 準(zhǔn)備售出狀態(tài)
final static int HasCoin = 2; // 已經(jīng)投了硬幣的狀態(tài)
final static int SoldState = 3; // 售出狀態(tài)
private int state = SoldOutState;
private int count = 0; // 內(nèi)部糖果的剩余數(shù)量
public CandyMachine(int count) {
this.count = count;
if (count > 0) {
state = OnReadyState;
}
}
/**
* 投入硬幣收奔,如果糖果機(jī)狀態(tài)是準(zhǔn)備售出掌呜,則可以搖動(dòng)把手購買糖果,其他的狀態(tài)則無法使用
*/
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;
}
}
/**
* 如果已經(jīng)投入硬幣之后則可以選擇退出硬幣
*/
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;
}
}
/**
* 如果已經(jīng)投入硬幣則可以搖動(dòng)把手
*/
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--;
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;
}
}
}
缺點(diǎn):各種行為耦合度較高坪哄,不利于新需求的拓展
三质蕉、狀態(tài)模式改進(jìn)
雖然傳統(tǒng)的面向?qū)ο竽J揭部蓾M足功能,但是若新增需求則不利于拓展翩肌。加入此項(xiàng)目新增一個(gè)幸運(yùn)者的功能模暗,售出糖果的時(shí)候有一定幾率成為幸運(yùn)者掉出兩顆糖果。
若滿足該功能念祭,則需在原本完成的糖果機(jī)代碼中修改兑宇,則易造成其他不必要的bug,則引出狀態(tài)模式:
- 定義一個(gè)狀態(tài)接口粱坤,接口定義需要處理的方法
- 定義不同狀態(tài)的接口對(duì)象隶糕,對(duì)象內(nèi)實(shí)現(xiàn)不同狀態(tài)對(duì)不同操作的處理
/**
* 狀態(tài)模式,統(tǒng)一的狀態(tài)接口站玄,接口內(nèi)實(shí)現(xiàn)不同狀態(tài)下不同的處理行為
*/
public interface State {
// 投入硬幣
public void insertCoin();
// 退出硬幣
public void returnCoin();
// 搖動(dòng)把手
public void turnCrank();
// 掉出糖果
public void dispense();
// 打印當(dāng)前狀態(tài)
public void printstate();
}
/**
* 狀態(tài)模式枚驻,新增的幸運(yùn)者狀態(tài),出糖果的時(shí)候有一定概率出兩顆
*/
public class WinnerState implements State {
private CandyMachine mCandyMachine;
public WinnerState(CandyMachine mCandyMachine) {
this.mCandyMachine = mCandyMachine;
}
@Override
public void insertCoin() {
System.out.println("please wait!we are giving you a candy!");
}
@Override
public void returnCoin() {
System.out.println("you haven't inserted a coin yet!");
}
@Override
public void turnCrank() {
System.out.println("we are giving you a candy,turning another get nothing,!");
}
@Override
public void dispense() {
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() {
System.out.println("***WinnerState***");
}
}
/**
* 狀態(tài)模式株旷,糖果機(jī)內(nèi)只定義狀態(tài)接口對(duì)象再登,在接口內(nèi)部給糖果機(jī)的狀態(tài)賦值
*/
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;
}
/**
* 糖果機(jī)的一切狀態(tài)都直接調(diào)用狀態(tài)接口內(nèi)部的方法
*/
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();
}
}
/**
* 狀態(tài)模式,通過定義一個(gè)狀態(tài)接口晾剖,接口內(nèi)實(shí)現(xiàn)不同狀態(tài)下不同的處理方式
* 則調(diào)用處理方式時(shí)直接調(diào)用狀態(tài)接口對(duì)象的實(shí)現(xiàn)方法
* 使用狀態(tài)模式可以是不同狀態(tài)接互不影響锉矢,也可便于新增多種狀態(tài)類型的需求
*/
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();
}
}
四、總結(jié)
在很多情況下齿尽,一個(gè)對(duì)象的行為取決于一個(gè)或多個(gè)動(dòng)態(tài)變化的屬性沈撞,這樣的屬性叫做狀態(tài),這樣的對(duì)象叫做有狀態(tài)的(stateful)對(duì)象雕什,這樣的對(duì)象狀態(tài)是從事先定義好的一系列值中取出的缠俺。當(dāng)一個(gè)這樣的對(duì)象與外部事件產(chǎn)生互動(dòng)時(shí),其內(nèi)部狀態(tài)就會(huì)改變贷岸,從而使得系統(tǒng)的行為也隨之發(fā)生變化壹士。
Java設(shè)計(jì)模式所有示例代碼,持續(xù)更新中