狀態(tài)模式(State Pattern)
基本介紹
- 狀態(tài)模式:它主要是用來解決對象在多種狀態(tài)轉(zhuǎn)換時,需要對外輸出不同的行為的問題,狀態(tài)和行為是一一對應(yīng)的,狀態(tài)之間可以相互轉(zhuǎn)換。
- 當(dāng)一個對象的內(nèi)在狀態(tài)改變時,允許改變其行為,這個對象看起來像是改變了其類。
原理類圖
說明:
- Context 類為環(huán)境角色,用于維護(hù)State實例,這個實例定義當(dāng)前狀態(tài)
- State是抽象狀態(tài)角色,定義一個接口封裝與Context的一個特點接口相關(guān)行為
- ConcreteState 具體的狀態(tài)角色,每個子類實現(xiàn)一個與Context的一個狀態(tài)相關(guān)行為
應(yīng)用實例
編寫一個程序完成App抽獎,具體要求如下:
- 假如沒菜價一個這個活動就要扣除50積分,中將概率是10%
- 獎品數(shù)量固定,抽完就不能抽獎。
- 活動有四個狀態(tài):可以抽獎,不能抽獎,發(fā)放獎品,和獎品領(lǐng)完。
- 活動的四個狀態(tài)轉(zhuǎn)換關(guān)系如圖:
思路分析
- 定義一個接口叫狀態(tài)接口,每個狀態(tài)都實現(xiàn)它。
- 接口有扣除積分,抽獎方法,發(fā)放獎品的方法。
類圖如下:
代碼如下:文章來源:http://www.zghlxwxcb.cn/news/detail-829191.html
public interface State {
// 扣除積分 - 50
public void deductMoney();
// 是否抽中獎品
public boolean raffle();
// 發(fā)放獎品
public void dispensePrize();
}
public class CanRaffleState implements State{
RaffleActivity activity;
public CanRaffleState(RaffleActivity activity) {
this.activity = activity;
}
//已經(jīng)扣除了積分,不能再扣
@Override
public void deductMoney() {
System.out.println("已經(jīng)扣取過了積分");
}
//可以抽獎, 抽完獎后,根據(jù)實際情況,改成新的狀態(tài)
@Override
public boolean raffle() {
System.out.println("正在抽獎,請稍等!");
Random r = new Random();
int num = r.nextInt(10);
// 10%中獎機(jī)會
if(num == 0){
// 改變活動狀態(tài)為發(fā)放獎品 context
activity.setState(activity.getDispenseState());
return true;
}else{
System.out.println("很遺憾沒有抽中獎品!");
// 改變狀態(tài)為不能抽獎
activity.setState(activity.getNoRafflleState());
return false;
}
}
// 不能發(fā)放獎品
@Override
public void dispensePrize() {
System.out.println("沒中獎,不能發(fā)放獎品");
}
}
public class NoRaffleState implements State{
// 初始化時傳入活動引用,扣除積分后改變其狀態(tài)
RaffleActivity activity;
public NoRaffleState(RaffleActivity activity) {
this.activity = activity;
}
// 當(dāng)前狀態(tài)可以扣積分 , 扣除后,將狀態(tài)設(shè)置成可以抽獎狀態(tài)
@Override
public void deductMoney() {
System.out.println("扣除50積分成功,您可以抽獎了");
activity.setState(activity.getCanRaffleState());
}
// 當(dāng)前狀態(tài)不能抽獎
@Override
public boolean raffle() {
System.out.println("扣了積分才能抽獎喔!");
return false;
}
// 當(dāng)前狀態(tài)不能發(fā)獎品
@Override
public void dispensePrize() {
System.out.println("不能發(fā)放獎品");
}
}
public class DispenseState implements State{
// 初始化時傳入活動引用,發(fā)放獎品后改變其狀態(tài)
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;
}
//發(fā)放獎品
@Override
public void dispensePrize() {
if(activity.getCount() > 0){
System.out.println("恭喜中獎了");
// 改變狀態(tài)為不能抽獎
activity.setState(activity.getNoRafflleState());
}else{
System.out.println("很遺憾,獎品發(fā)送完了");
// 改變狀態(tài)為獎品發(fā)送完畢, 后面我們就不可以抽獎
activity.setState(activity.getDispensOutState());
//System.out.println("抽獎活動結(jié)束");
//System.exit(0);
}
}
}
public class DispenseOutState implements State{
// 初始化時傳入活動引用
RaffleActivity activity;
public DispenseOutState(RaffleActivity activity) {
this.activity = activity;
}
@Override
public void deductMoney() {
System.out.println("獎品發(fā)送完了,請下次再參加");
}
@Override
public boolean raffle() {
System.out.println("獎品發(fā)送完了,請下次再參加");
return false;
}
@Override
public void dispensePrize() {
System.out.println("獎品發(fā)送完了,請下次再參加");
}
}
public class RaffleActivity {
// state 表示活動當(dāng)前的狀態(tài),是變化
State state = null;
// 獎品數(shù)量
int count = 0;
// 四個屬性,表示四種狀態(tài)
State noRafflleState = new NoRaffleState(this);
State canRaffleState = new CanRaffleState(this);
State dispenseState = new DispenseState(this);
State dispensOutState = new DispenseOutState(this);
//構(gòu)造器
//1. 初始化當(dāng)前的狀態(tài)為 noRafflleState(即不能抽獎的狀態(tài))
//2. 初始化獎品的數(shù)量
public RaffleActivity( int count) {
this.state = getNoRafflleState();
this.count = count;
}
//扣分, 調(diào)用當(dāng)前狀態(tài)的 deductMoney
public void debuctMoney(){
state.deductMoney();
}
//抽獎
public void raffle(){
// 如果當(dāng)前的狀態(tài)是抽獎成功
if(state.raffle()){
//領(lǐng)取獎品
state.dispensePrize();
}
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
//這里請大家注意,每領(lǐng)取一次獎品,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;
}
}
注意事項
- 代碼有很強(qiáng)的可讀性。狀態(tài)模式將每個狀態(tài)的行為封裝到對應(yīng)的一個類中。
- 方便維護(hù)。將容易產(chǎn)生問題的if-else語句刪除了,如果把狀態(tài)的行為放到一個類中,沒調(diào)用方法時都要判斷當(dāng)前時什么狀態(tài),不但會產(chǎn)生很多if-else語句,而且容易出錯。
- 符合開閉原則,容易增刪狀態(tài)。
- 會產(chǎn)生很多類,每個狀態(tài)都要一個對應(yīng)的類,當(dāng)狀態(tài)過多時會產(chǎn)生很多類,加大維護(hù)難度。
應(yīng)用場景
當(dāng)一個事件或者狀態(tài)有很多種狀態(tài),狀態(tài)之間需要相互轉(zhuǎn)換,對不同的狀態(tài)要求有不同的行為的時候,可以考慮使用該模式。文章來源地址http://www.zghlxwxcb.cn/news/detail-829191.html
到了這里,關(guān)于java設(shè)計模式之狀態(tài)模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!