原文地址:LoveDev
一個(gè)對(duì)象的行為其屬性的動(dòng)態(tài)變化蜀踏,這樣的屬性叫狀態(tài)屋摇,這類對(duì)象也叫做有狀態(tài)的對(duì)象偶洋。當(dāng)此類對(duì)象被某一事件修改其內(nèi)部狀態(tài)時(shí)晾嘶,程序的行為也要隨之改變
狀態(tài)模式又稱狀態(tài)對(duì)象模式(Pattern of Objects for States)是用于解決對(duì)象的復(fù)雜狀態(tài)及不同狀態(tài)下的行為的一種模式妓雾。
模式定義
狀態(tài)模式允許一個(gè)對(duì)象在其內(nèi)部屬性改變的時(shí)候改變其行為,這個(gè)對(duì)象看上去就像是改變了它的類一樣
模式結(jié)構(gòu)
狀態(tài)模式涉及角色:
- 環(huán)境角色(Context):定義客戶感興趣的接口垒迂,并保留一個(gè)具體狀態(tài)類的實(shí)例
- 抽象狀態(tài)角色(State):定義一個(gè)借口械姻,封裝特定狀態(tài)下的對(duì)應(yīng)行為
- 具體狀態(tài)角色(ConcreteState):抽象狀態(tài)角色的子類,每個(gè)子類實(shí)現(xiàn)了相關(guān)的行為
Tip:
- 該圖為UML圖
- 類包含3個(gè)組成部分机断,第一欄為類名楷拳,第二欄為屬性绣夺,第三欄為方法
- 屬性和方法前可加一個(gè)可見(jiàn)性修飾符,
+
號(hào)表示public
修飾符唯竹,-
號(hào)表示private
修飾符乐导,#
號(hào)表示protected
修飾符,省略表示包級(jí)可見(jiàn)浸颓。 - 接口包含2個(gè)組成部分物臂,第一欄為接口名,第二欄為方法产上,在接口名之上加上
<<interface>>
使用場(chǎng)景
比如游戲中一個(gè)用戶的用過(guò)外掛違規(guī)次數(shù)屬性棵磷,如果用戶用過(guò)1~3次,每次警告制裁晋涣;3次以上仪媒,每次封號(hào)3天;5次以上谢鹊,每次封號(hào)1周算吩;到達(dá)10次,永久封號(hào)佃扼。
根據(jù)以上描述可以分為四種狀態(tài):
- 警告
- 封號(hào)3天
- 封號(hào)1周
- 永久封號(hào)
源碼
環(huán)境角色
public class PunishManager {
//保存違規(guī)用戶及次數(shù)
private Map<String, Integer> mPunishMap = new HashMap<>();
/**
* 獲取違規(guī)用戶及次數(shù)
*/
Map<String, Integer> getPunishMap() {
return mPunishMap;
}
/**
* 獲取具體狀態(tài)角色偎巢,封裝轉(zhuǎn)換規(guī)則
*
* @param oldPunishCount 違規(guī)次數(shù)
* @return 具體狀態(tài)角色
*/
private PunishState getPunishState(Integer oldPunishCount) {
//推薦盡量少用else,如果超過(guò)3層if-else代碼推薦使用衛(wèi)語(yǔ)句
if (oldPunishCount <= 3) {
return new LowPunishState();
}
if (oldPunishCount <= 5) {
return new MidPunishState();
}
if (oldPunishCount < 10) {
return new HeightPunishState();
}
return new BlackPunishState();
}
/**
* 違規(guī)處理
*
* @param uid 用戶ID
*/
public void punish(String uid) {
//獲取之前違規(guī)次數(shù)
Integer oldPunishCount = mPunishMap.get(uid);
if (oldPunishCount == null) {
oldPunishCount = 0;
}
oldPunishCount += 1;
mPunishMap.put(uid, oldPunishCount);
//獲取對(duì)應(yīng)狀態(tài)對(duì)象進(jìn)行響應(yīng)操作
getPunishState(oldPunishCount).punish(uid, oldPunishCount, this);
}
}
抽象狀態(tài)角色
public interface PunishState {
/**
* 違規(guī)處理
*
* @param uid 用戶ID
* @param violationCount 違規(guī)次數(shù)
* @param punishManager 環(huán)境角色
*/
public void punish(String uid, int violationCount, PunishManager punishManager);
}
具體狀態(tài)角色
根據(jù)不同的具體狀態(tài)角色做相應(yīng)的業(yè)務(wù)
public class LowPunishState implements PunishState {
@Override
public void punish(String uid, int violationCount, PunishManager punishManager) {
//違規(guī)1~3次兼耀,警告制裁
System.out.println("警告制裁");
}
}
public class MidPunishState implements PunishState {
@Override
public void punish(String uid, int violationCount, PunishManager punishManager) {
//違規(guī)3次以上压昼,封號(hào)三天
System.out.println("封號(hào)三天");
}
}
public class HeightPunishState implements PunishState {
@Override
public void punish(String uid, int violationCount, PunishManager punishManager) {
//違規(guī)5次以上,封號(hào)一周
System.out.println("封號(hào)一周");
}
}
public class BlackPunishState implements PunishState {
@Override
public void punish(String uid, int violationCount, PunishManager punishManager) {
//違規(guī)10次瘤运,永久封號(hào)
System.out.println("永久封號(hào)");
}
}
入口類
public class Main {
public static void main(String[] args) {
PunishManager punishManager = new PunishManager();
for (int i = 1; i <= 10; i++) {
punishManager.punish("Kevin");
}
}
}
運(yùn)行結(jié)果:
優(yōu)點(diǎn)
- 封裝了轉(zhuǎn)換規(guī)則
- 結(jié)構(gòu)清晰窍霞,提高可維護(hù)性
- 不同狀態(tài)對(duì)應(yīng)的不同行為放到單獨(dú)類中,方便增加新的狀態(tài)拯坟,只需改變對(duì)象狀態(tài)即可改變對(duì)象行為
缺點(diǎn)
- 增加了類和對(duì)象的個(gè)數(shù)
- 狀態(tài)模式對(duì)“開(kāi)閉原則”的支持并不太好但金,對(duì)于可以切換狀態(tài)的狀態(tài)模式,增加新的狀態(tài)類需要修改那些負(fù)責(zé)狀態(tài)轉(zhuǎn)換的源代碼似谁,否則無(wú)法切換到新增狀態(tài)傲绣;而且修改某個(gè)狀態(tài)類的行為也需修改對(duì)應(yīng)類的源代碼。