設(shè)計(jì)模式-狀態(tài)模式

原文地址: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)類的源代碼。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巩踏,一起剝皮案震驚了整個(gè)濱河市秃诵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌塞琼,老刑警劉巖菠净,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡毅往,警方通過(guò)查閱死者的電腦和手機(jī)牵咙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)攀唯,“玉大人洁桌,你說(shuō)我怎么就攤上這事『钹郑” “怎么了另凌?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)戒幔。 經(jīng)常有香客問(wèn)我吠谢,道長(zhǎng),這世上最難降的妖魔是什么诗茎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任工坊,我火速辦了婚禮,結(jié)果婚禮上敢订,老公的妹妹穿的比我還像新娘王污。我一直安慰自己,他們只是感情好楚午,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布玉掸。 她就那樣靜靜地躺著,像睡著了一般醒叁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泊业,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天把沼,我揣著相機(jī)與錄音,去河邊找鬼吁伺。 笑死饮睬,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的篮奄。 我是一名探鬼主播捆愁,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼窟却!你這毒婦竟也來(lái)了昼丑?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤夸赫,失蹤者是張志新(化名)和其女友劉穎菩帝,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡呼奢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年宜雀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片握础。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辐董,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出禀综,到底是詐尸還是另有隱情简烘,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布菇存,位于F島的核電站夸研,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏依鸥。R本人自食惡果不足惜亥至,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贱迟。 院中可真熱鬧姐扮,春花似錦、人聲如沸衣吠。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)缚俏。三九已至惊搏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間忧换,已是汗流浹背恬惯。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留亚茬,地道東北人酪耳。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓综芥,卻偏偏與公主長(zhǎng)得像负乡,于是被迫代替她去往敵國(guó)和親哲银。 傳聞我的和親對(duì)象是個(gè)殘疾皇子昆禽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容