設計模式學習筆記之狀態模式
什麼是狀態模式呢?
允許一個物件在其內部狀態改變時改變它的行為。物件看起來似乎修改了它的類。。。是不是聽起來顯示在內部進行零件調換的感覺,其實是有點類似這種想法的,只不過調換的零件就是封裝好的狀態。
讓我們來舉個例子
在我還上學的時候,寢室樓下有一臺這樣的自動販售機,專門賣飲料。每天晚上寢室關門之後口渴了,在這裡面買點飲料喝喝還是很方便的。
下面用程式來模擬一下這個售貨機:
可樂售貨機類:
/**
*
* 可樂自動販售機類
* @author birdlove1987
*
*/
public class VendingMachine
{
//售空
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 VendingMachine(int count)
{
this.count = count;
if (count > 0) {
state = OnReadyState;
}
}
//向販售機投幣函式
public void insertCoin()
{
switch (state)
{
case SoldOutState:
System.out.println("請不要投幣了,售貨機裡已經沒有可樂了!");
break;
case OnReadyState:
state = HasCoin;
System.out.println("投幣成功,請按出貨按鈕!");
break;
case HasCoin:
System.out.println("售貨機裡以及有硬幣了,請勿重複投幣!");
break;
case SoldState:
System.out.println("正在出貨請勿投幣!");
break;
}
}
//販售機退幣函式
public void returnCoin()
{
switch (state)
{
case SoldOutState:
System.out.println("您還沒有投幣!");
break;
case OnReadyState:
System.out.println("您還沒有投幣!");
break;
case HasCoin:
System.out.println("請在退幣口收好您的硬幣");
state = OnReadyState;
break;
case SoldState:
System.out.println("可樂已售出,不能退幣");
break;
}
}
//按出可樂按鈕函式
public void pressButton()
{
switch (state)
{
case SoldOutState:
System.out.println("對不起,可樂已售空!");
break;
case OnReadyState:
System.out.println("請您先投幣!");
break;
case HasCoin:
System.out.println("請稍等,出可樂中!");
state = SoldState;
appearCola();
break;
case SoldState:
System.out.println("可樂已出,如想再次購買請再次投幣!");
break;
}
}
//售貨機出可樂函式
private void appearCola()
{
count = count - 1;
System.out.println("出貨口,滾出了一瓶可樂!");
if (count > 0)
{
state = OnReadyState;
}
else
{
System.out.println("對不起,可樂已經售空了,請勿在投幣!");
state = SoldOutState;
}
}
//列印目前售貨機的狀態
public void printState()
{
switch (state)
{
case SoldOutState:
System.out.println("=========售空=========");
break;
case OnReadyState:
System.out.println("=========售賣中=========");
break;
case HasCoin:
System.out.println("=========已投幣=========");
break;
case SoldState:
System.out.println("=========出貨中=========");
break;
}
}
}
測試類
/**
* 測試類
* @author birdlove1987
*
*/
public class MainTest
{
public static void main(String[] args)
{
//建立售貨機例項,並且只放入一瓶可樂
VendingMachine mVendingMachine=new VendingMachine(1);
//列印售貨機狀態
mVendingMachine.printState();
//投幣
mVendingMachine.insertCoin();
//列印售貨機狀態
mVendingMachine.printState();
//按出貨按鈕
mVendingMachine.pressButton();
//列印售貨機狀態
mVendingMachine.printState();
//投幣
mVendingMachine.insertCoin();
//列印售貨機狀態
mVendingMachine.printState();
//按出貨按鈕
mVendingMachine.pressButton();
//列印售貨機狀態
mVendingMachine.printState();
}
}
嗯!模擬成功了!好像感覺還不錯呢!不過買了一段時間,你可能發現,如果不搞一些促銷活動,更本就搞不過那些有促銷的商家!
所以自動售貨機也要搞一個“再來一瓶”的活動啊!
但是!!!如果現在直接在自動售貨機的類上去直接修改,就違背了軟體設計裡的“開-閉原則”了,破壞了我們已經閉合的類。所以現在看來,這種設計並不好。。
下面就輪到狀態設計模式登場啦,我們從新構建類,這次以狀態為類,來構建。
首先定義一下狀態介面
/***
* 狀態介面
* @author birdlove1987
*
*/
public interface State
{
//投幣函式
public void insertCoin();
//退幣函式
public void returnCoin();
//按出可樂按鈕函式
public void pressButton();
//出可樂函式
public void appearCola();
//列印狀態函式
public void printState();
}
/***
* 在售狀態類
* @author birdlove1987
*
*/
public class OnReadyState implements State
{
//販售機引用
private VendingMachine mVendingMachine;
//建構函式初始化
public OnReadyState(VendingMachine mVendingMachine)
{
this.mVendingMachine=mVendingMachine;
}
@Override
public void insertCoin()
{
// TODO Auto-generated method stub
System.out.println("投幣成功,請按出貨按鈕!");
mVendingMachine.setState(mVendingMachine.mHasCoin);
}
@Override
public void returnCoin()
{
// TODO Auto-generated method stub
System.out.println("您還沒有投幣!");
}
@Override
public void pressButton()
{
// TODO Auto-generated method stub
System.out.println("請您先投幣!");
}
@Override
public void appearCola()
{
// TODO Auto-generated method stub
}
@Override
public void printState()
{
// TODO Auto-generated method stub
System.out.println("=========售賣中=========");
}
}
/***
* 售空狀態類
* @author birdlove1987
*
*/
public class SoldOutState implements State
{
private VendingMachine mVendingMachine;
public SoldOutState(VendingMachine mCandyMachine)
{
this.mVendingMachine=mVendingMachine;
}
@Override
public void insertCoin()
{
// TODO Auto-generated method stub
System.out.println("請不要投幣了,售貨機裡已經沒有可樂了!");
}
@Override
public void returnCoin()
{
// TODO Auto-generated method stub
System.out
.println("您還沒有投幣!");
}
@Override
public void pressButton()
{
// TODO Auto-generated method stub
System.out.println("對不起,可樂已售空!");
}
@Override
public void appearCola()
{
// TODO Auto-generated method stub
}
@Override
public void printState() {
// TODO Auto-generated method stub
System.out.println("=========售空=========");
}
}
/***
* 已投幣狀態類
* @author birdlove1987
*
*/
public class HasCoin implements State
{
private VendingMachine mVendingMachine;
public HasCoin(VendingMachine mVendingMachine)
{
this.mVendingMachine = mVendingMachine;
}
@Override
public void insertCoin()
{
// TODO Auto-generated method stub
System.out.println("售貨機裡以及有硬幣了,請勿重複投幣!");
}
@Override
public void returnCoin()
{
// TODO Auto-generated method stub
System.out.println("請在退幣口收好您的硬幣");
mVendingMachine.setState(mVendingMachine.mOnReadyState);
}
@Override
public void pressButton()
{
// TODO Auto-generated method stub
System.out.println("請稍等,出可樂中!");
//建立隨機中獎概率
Random anotherOne = new Random();
//20%的機會再來一瓶
int luck = anotherOne.nextInt(5);
if(luck==0)
{
mVendingMachine.setState(mVendingMachine.mOneMoreCola);
}else
{
mVendingMachine.setState(mVendingMachine.mSoldState);
}
}
@Override
public void appearCola()
{
}
@Override
public void printState()
{
// TODO Auto-generated method stub
System.out.println("=========已投幣=========");
}
}
/**
* 出可樂狀態類
* @author birdlove1987
*
*/
public class SoldState implements State
{
private VendingMachine mVendingMachine;
public SoldState(VendingMachine mVendingMachine)
{
this.mVendingMachine=mVendingMachine;
}
@Override
public void insertCoin()
{
// TODO Auto-generated method stub
System.out.println("正在出貨請勿投幣!");
}
@Override
public void returnCoin()
{
// TODO Auto-generated method stub
System.out.println("可樂已售出,不能退幣");
}
@Override
public void pressButton()
{
// TODO Auto-generated method stub
System.out
.println("可樂已出,如想再次購買請再次投幣!");
}
@Override
public void appearCola()
{
// TODO Auto-generated method stub
mVendingMachine.appearCola();
if (mVendingMachine.getCount() > 0)
{
mVendingMachine.setState(mVendingMachine.mOnReadyState);
}
else
{
System.out.println("對不起,可樂已經售空了,請勿在投幣!");
mVendingMachine.setState(mVendingMachine.mSoldOutState);
}
}
@Override
public void printState()
{
// TODO Auto-generated method stub
System.out.println("=========出貨中=========");
}
}
/***
* 再來一瓶類
* @author birdlove1987
*
*/
public class OneMoreCola implements State
{
private VendingMachine mVendingMachine;
public OneMoreCola(VendingMachine mVendingMachine)
{
this.mVendingMachine = mVendingMachine;
}
@Override
public void insertCoin()
{
// TODO Auto-generated method stub
System.out.println("正在出貨請勿投幣!");
}
@Override
public void returnCoin()
{
// TODO Auto-generated method stub
System.out.println("可樂已售出,不能退幣");
}
@Override
public void pressButton()
{
// TODO Auto-generated method stub
System.out.println("請稍等,出可樂中!");
}
@Override
public void appearCola()
{
// TODO Auto-generated method stub
mVendingMachine.appearCola();
if (mVendingMachine.getCount() == 0)
{
mVendingMachine.setState(mVendingMachine.mSoldOutState);
}
else
{
System.out.println("恭喜你獲得了再來一瓶,馬上為您再出一瓶可樂");
mVendingMachine.appearCola();
if (mVendingMachine.getCount() > 0)
{
mVendingMachine.setState(mVendingMachine.mOnReadyState);
}
else
{
System.out.println("對不起,可樂已經售空了,請勿在投幣!");
mVendingMachine.setState(mVendingMachine.mSoldOutState);
}
}
}
@Override
public void printState()
{
// TODO Auto-generated method stub
System.out.println("=========再來一瓶=========");
}
}
/**
* 自動售貨機類
* @author birdlove1987
*
*/
public class VendingMachine
{
//狀態類引用
State mSoldOutState;
State mOnReadyState;
State mHasCoin;
State mSoldState;
State mOneMoreCola;
//目前狀態
private State state;
//可樂計數器
private int count = 0;
//建構函式
public VendingMachine(int count)
{
this.count = count;
mSoldOutState = new SoldOutState(this);
mOnReadyState = new OnReadyState(this);
mHasCoin = new HasCoin(this);
mSoldState = new SoldState(this);
mOneMoreCola = new OneMoreCola(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 pressButton()
{
state.pressButton();
state.appearCola();
}
//出可樂函式
void appearCola()
{
// TODO Auto-generated method stub
if (count > 0)
{
count = count - 1;
System.out.println("出貨口,滾出了一瓶可樂!");
}
}
//可樂計數函式
public int getCount()
{
return count;
}
//列印狀態函式
public void printState()
{
state.printState();
}
}
/**
* 測試類
* @author birdlove1987
*
*/
public class MainTest
{
public static void main(String[] args)
{
//例項化自動販售機物件
VendingMachine mVendingMachine = new VendingMachine(10);
//列印狀態
mVendingMachine.printState();
//投幣
mVendingMachine.insertCoin();
//列印狀態
mVendingMachine.printState();
//按出可樂按鈕
mVendingMachine.pressButton();
//列印狀態
mVendingMachine.printState();
//投幣
mVendingMachine.insertCoin();
//列印狀態
mVendingMachine.printState();
//按出可樂按鈕
mVendingMachine.pressButton();
//列印狀態
mVendingMachine.printState();
}
}
臥槽!一次都沒中獎,什麼鬼!!!不行,買買買!!!
中了一次。。。好吧,我來作弊一下。。調到100%
哈哈哈!
狀態模式的優點
1.狀態模式將與特定狀態相關的行為區域性化,並且將不同狀態的行為分割開來。
2.將與狀態有關的行為封裝到一個類中,方便地增加新的狀態,只需改變物件狀態即可改變物件的行為。
3.提供程式碼複用性,降低了程式的某些耦合性。
狀態模式的缺點
1.有時候狀態類會很多,而且邏輯複雜。
狀態模式適用場景
1、物件的行為依賴於它的狀態,並且其行為依據它的狀態改變而改變。
2、程式碼中包含大量與物件狀態有關的條件語句。
相關文章
- 設計模式學習筆記(二十)狀態模式及其實現設計模式筆記
- 設計模式學習筆記之策略模式設計模式筆記
- 我學設計模式 之 狀態模式設計模式
- 設計模式學習筆記之工廠模式設計模式筆記
- 設計模式學習筆記之迭代器模式設計模式筆記
- 設計模式學習筆記之單例模式設計模式筆記單例
- 設計模式之——狀態模式設計模式
- 設計模式學習筆記之裝飾者模式設計模式筆記
- 設計模式學習筆記之介面卡模式設計模式筆記
- PHP 設計模式之狀態模式PHP設計模式
- 設計模式之狀態模式(State)設計模式
- 設計模式20之狀態模式設計模式
- Java設計模式之狀態模式Java設計模式
- 設計模式系列之「狀態模式」設計模式
- 學習筆記-設計模式:MVC模式筆記設計模式MVC
- 設計模式學習筆記設計模式筆記
- 學習筆記-設計模式筆記設計模式
- 設計模式漫談之狀態模式設計模式
- C#設計模式之狀態模式C#設計模式
- 設計模式系列之十二狀態模式設計模式
- 設計模式之狀態模式---State Pattern設計模式
- Javascript 設計模式系統講解與應用——學習筆記10-狀態模式JavaScript設計模式筆記
- 設計模式學習筆記——單例模式設計模式筆記單例
- 軟體設計模式學習(二十四)狀態模式設計模式
- Java設計模式學習筆記(一) 設計模式概述Java設計模式筆記
- 設計模式之狀態模式(三分鐘學會一個設計模式)設計模式
- 設計模式-狀態模式設計模式
- 設計模式:狀態模式設計模式
- JavaScript設計模式學習筆記JavaScript設計模式筆記
- php設計模式學習筆記PHP設計模式筆記
- 折騰Java設計模式之狀態模式Java設計模式
- Unity【話大】設計模式之狀態模式Unity設計模式
- JAVA設計模式之 狀態模式【State Pattern】Java設計模式
- 【設計模式】設計模式學習筆記之(一)——類圖、物件之間的關係及設計模式概要設計模式筆記物件
- 設計模式(十五)狀態模式設計模式
- javascript設計模式狀態模式JavaScript設計模式
- 設計模式(六):狀態模式設計模式
- Java設計模式學習筆記(五) 單例模式Java設計模式筆記單例