圖解Java設計模式之狀態模式
- APP抽象活動問題
- 狀態模式基本介紹
- 狀態模式的原理類圖
- 狀態模式解決APP抽獎問題
- 狀態模式的注意事項和細節
APP抽象活動問題
請撰寫程式完成APP抽象活動,具體要求如下 :
1)加入每參加一個這個活動要扣除用戶50積分,中獎概率是10%,
2)獎品數量固定,抽完就不能抽獎,
3)活動有四個狀態 :可以抽象、不能抽象、發放獎品和獎品領完,
4)活動的四個狀態轉換關系圖(右圖)
狀態模式基本介紹
1)狀態模式(State Pattern):它主要用來解決物件在多種狀態轉換時,需要對外輸出不同的行為的問題,狀態和行為是一一對應的,狀態之間可以相互轉換,
2)當一個物件的內在狀態改變時,允許改變其行為,這個物件看起來像是改變類其類,
狀態模式的原理類圖

對原理類圖的說明 :
1)Context 類為環境角色,用于維護State 實體,這個實體定義當前狀態,
2)State 是抽象狀態角色,定義一個介面封裝與Context 的一個特點介面相關行為,
3)ConcreteState 具體的狀態角色,每個子類實作一個與Context 的一個狀態相關行為,
狀態模式解決APP抽獎問題
1)應用實體要求
完成APP抽象活動專案,使用狀態模式,
2)類圖
定義出一個介面叫狀態介面,每個狀態都實作它,
介面有扣除積分方法、抽象方法、發放獎品方法
package com.example.demo.state;
/**
* 狀態抽象類
* @author zhaozhaohai
*
*/
public abstract class State {
// 扣除積分 - 50
public abstract void deductMoney();
// 是否抽中獎品
public abstract boolean raffle();
// 發放獎品
public abstract void dispensePrize();
}
package com.example.demo.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
activity.setState(activity.getDispenseState());
return true;
}else{
System.out.println("很遺憾沒有抽中獎品!"); // 改變狀態為不能抽獎
activity.setState(activity.getNoRafflleState());
return false;
}
}
// 不能發放獎品
@Override
public void dispensePrize() {
System.out.println("沒中獎,不能發放獎品");
}
}
package com.example.demo.state;
public class RaffleActivity {
// state 表示活動當前的狀態,是變化
State state = null;
// 獎品數量
int count = 0;
// 四個屬性,表示四種狀態
State noRafflleState = new NoRaffleState(this);
State canRaffleState = new CanRaffleState(this);
State dispenseState = new DispenseState(this);
State dispensOutState = new DispenseOutState(this);
//構造器
//1. 初始化當前的狀態為 noRafflleState(即不能抽獎的狀態)
//2. 初始化獎品的數量
public RaffleActivity( int count) {
this.state = getNoRafflleState();
this.count = count;
}
//扣分, 呼叫當前狀態的 deductMoney
public void debuctMoney(){
state.deductMoney();
}
//抽獎
public void raffle(){
// 如果當前的狀態是抽獎成功
if(state.raffle()){
//領取獎品
state.dispensePrize();
}
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
//這里請大家注意,每領取一次獎品,count--
public int getCount() {
int curCount = count;
count--;
return curCount;
}
public void setCount(int count) {
this.count = count;
}
public State getNoRafflleState() {
return noRafflleState;
}
public void setNoRafflleState(State noRafflleState) {
this.noRafflleState = noRafflleState;
}
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 getDispensOutState() {
return dispensOutState;
}
public void setDispensOutState(State dispensOutState) {
this.dispensOutState = dispensOutState;
}
}
package com.example.demo.state;
/**
* 獎品發放完畢狀態
* 說明,當我們 activity 改變成 DispenseOutState, 抽獎活動結束
* @author zhaozhaohai
*
*/
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("獎品發送完了,請下次再參加");
// TODO Auto-generated method stub
return false;
}
@Override
public void dispensePrize() {
// TODO Auto-generated method stub
System.out.println("獎品發送完了,請下次再參加");
}
}
package com.example.demo.state;
/**
* 發放獎品的狀態
* @author zhaozhaohai
*
*/
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.getNoRafflleState());
}else{
System.out.println("很遺憾,獎品發送完了");
// 改變狀態為獎品發送完畢, 后面我們就不可以抽獎
activity.setState(activity.getDispensOutState());
//System.out.println("抽獎活動結束");
//System.exit(0);
}
}
}
package com.example.demo.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.example.demo.state;
public class ClientTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 創建活動物件,獎品有 1 個獎品
RaffleActivity activity = new RaffleActivity(1);
// 我們連續抽 300 次獎
for (int i = 0; i < 30; i++) {
System.out.println("--------第" + (i + 1) + "次抽獎----------");
// 參加抽獎,第一步點擊扣除積分
activity.debuctMoney();
// 第二步抽獎
activity.raffle();
}
}
}
狀態模式的注意事項和細節
1)代碼有很強的可讀性,狀態模式將每個狀態的行為封裝到對應的一個類中,
2)方便維護,將容易產生問題的 if - else 陳述句洗掉了,如果把每個狀態的行為都放到一個類中,每次呼叫方法時都要判斷當前是什么狀態,不但會產出很多if - else陳述句,而且容易出錯,
3)符合 “開閉原則”,容易增刪狀態,
4)會產生很多類,每個狀態都要一個對應的類,當狀態過多時會產生很多類,加大維護難度,
5)應用場景 :當一個事件或者物件很很多種狀態,狀態之間會相互依賴,對不同的狀態要求有不同的行為的時候,可以考慮使用狀態模式,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/16308.html
標籤:設計模式
下一篇:圖解Java設計模式之策略模式
