我國新發現一顆彗星,2 年多後將來到近日點
阿新 • • 發佈:2021-10-12
狀態模式基本介紹
1.狀態模式(State Pattern):它主要用來解決物件在多種狀態轉換時,需要對外輸出不同的行為的問題。狀態和行為是一一對應的,狀態之間可以相互轉換
2.當一個物件的內在狀態改變時,允許改變其行為,這個物件看起來像是改變了其類
狀態模式原理類圖
原理類圖說明
1.Context類為環境角色,用於維護State例項,這個例項定義當前狀態
2.State是抽象狀態角色,定義一個介面封裝的Context的一個特點介面相關行為
3.ConcreteState具體的狀態角色,每個子類實現一個Context的一個相關狀態行為
APP抽獎活動
具體要求:
1.假如每參加一次這個活動要扣除使用者50積分,中獎概率是10% 2.獎品數量固定,抽完就不能抽獎 3.活動有四個狀態:可以抽獎、不能抽獎、發放獎品和獎品領完
狀態轉換關係圖
程式碼實現
package com.cedric.state;
/**
* 狀態抽象類
*/
public abstract class State {
// 扣除積分 -50
public abstract void deductMoney();
// 是否抽中獎品
public abstract boolean raffle();
// 發放獎品
public abstract void dispensePrize();
}
package com.cedric.state; import java.util.Random; /** * 可以抽獎的狀態 */ public class CanRaffleState extends State{ RaffleActivity activity; public CanRaffleState(RaffleActivity activity){ this.activity = activity; } // 已經扣除積分了,不能再扣 @Override public void deductMoney() { System.out.println("已經扣取過積分了"); } // 可以抽獎,抽完獎後根據實際情況改成新的狀態 @Override public boolean raffle() { System.out.println("正在抽獎,請稍等!"); Random r = new Random(); int num = r.nextInt(10); // 10%中獎機會 if(num == 0){ // 改變活動狀態為發放獎品 context System.out.println("抽中了"); activity.setState(activity.getDispenseState()); return true; } else{ System.out.println("很遺憾沒有抽中獎品"); // 改變狀態為不能發放獎品 activity.setState(activity.getNoRaffleState()); return false; } } // 不能發放獎品 @Override public void dispensePrize() { System.out.println("沒中獎,不能發放獎品"); } } package com.cedric.state; /** * 不能抽獎狀態 */ public class NoRaffleState extends State{ // 初始化時傳入活動物件,扣除積分後改變其狀態 RaffleActivity activity; public NoRaffleState(RaffleActivity activity) { this.activity = activity; } // 當前狀態可以扣積分,扣除後將狀態設定成可以抽獎狀態 @Override public void deductMoney() { System.out.println("扣除50積分成功,您可以抽獎了"); activity.setState(activity.getCanRaffleState()); } // 當前狀態不能抽獎 @Override public boolean raffle() { System.out.println("扣了積分才能進行抽獎~"); return false; } // 當前狀態不能發放獎品 @Override public void dispensePrize() { System.out.println("不能發放獎品"); } } package com.cedric.state; /** * 發放獎品的狀態 */ public class DispenseState extends State{ RaffleActivity activity; public DispenseState(RaffleActivity activity) { this.activity = activity; } @Override public void deductMoney() { System.out.println("不能扣除積分"); } @Override public boolean raffle() { System.out.println("不能抽獎"); return false; } // 發放獎品 @Override public void dispensePrize() { if(activity.getCount() > 0){ System.out.println("恭喜中獎了"); // 改變狀態為不能抽獎 activity.setState(activity.getNoRaffleState()); } else { System.out.println("很遺憾,獎品傳送完了"); // 改變狀態為獎品傳送完畢 activity.setState(activity.getDispenseOutState()); System.out.println("抽獎活動結束"); System.exit(0); } } } package com.cedric.state; /** * 獎品發放完畢狀態 */ public class DispenseOutState extends State{ // 初始化時傳入活動引用 RaffleActivity activity; public DispenseOutState(RaffleActivity activity) { this.activity = activity; } @Override public void deductMoney() { System.out.println("獎品傳送完了,請下次再參加"); } @Override public boolean raffle() { System.out.println("獎品傳送完了,請下次再參加"); return false; } @Override public void dispensePrize() { System.out.println("獎品傳送完了,請下次再參加"); } }
package com.cedric.state; /** * 抽獎活動 */ public class RaffleActivity { // state表示活動當前的狀態 State state = null; // 獎品數量 int count = 0; // 四種狀態 State noRaffleState = new NoRaffleState(this); State canRaffleState = new CanRaffleState(this); State dispenseState = new DispenseState(this); State dispenseOutState = new DispenseOutState(this); // 初始化當前狀態為noRaffleState // 初始化獎品數量 public RaffleActivity(int count){ this.state = getNoRaffleState(); this.count = count; } //扣分,呼叫當前的狀態deductMoney public void deductMoney(){ state.deductMoney(); } public void raffle(){ // 如果當前狀態是抽獎成功 if(state.raffle()){ // 領取獎品 state.dispensePrize(); } } public State getState() { return state; } public void setState(State state) { this.state = state; } public int getCount() { int curCount = count; count--; return count; } public void setCount(int count) { this.count = count; } public State getNoRaffleState() { return noRaffleState; } public void setNoRaffleState(State noRaffleState) { this.noRaffleState = noRaffleState; } public State getCanRaffleState() { return canRaffleState; } public void setCanRaffleState(State canRaffleState) { this.canRaffleState = canRaffleState; } public State getDispenseState() { return dispenseState; } public void setDispenseState(State dispenseState) { this.dispenseState = dispenseState; } public State getDispenseOutState() { return dispenseOutState; } public void setDispenseOutState(State dispenseOutState) { this.dispenseOutState = dispenseOutState; } }
package com.cedric.state;
public class Client {
public static void main(String[] args) {
RaffleActivity activity = new RaffleActivity(1);
for (int i = 0; i < 30; i++) {
System.out.println("---------------第" + (i + 1) + "次抽獎-----------------");
// 參加抽獎,第一步點選扣除積分
activity.deductMoney();
// 第二步抽獎
activity.raffle();
}
}
}
狀態模式注意事項和細節
1.程式碼有很強的可讀性,狀態模式將每個狀態的行為封裝到對應的一個類中 2.方便維護,將容易產生問題的if-else語句刪除了,如果把每個狀態的行為都放到一個類中,每次呼叫方法 時都要判斷當前是什麼狀態,不但會產出很多if-else語句,而且容易出錯 3.符合OCP原則,容易增刪狀態 4.會產生很多類,每個狀態都有一個對應的類,當狀態過多時會產生很多類,加大維護難度 5.當一個事件或者物件有很多種狀態,狀態之間會相互轉換,對不同的狀態要求有不同的行為的時候,可以考慮使用狀態模式