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

原文地址:LoveDev

一個(gè)對(duì)象的行為其屬性的動(dòng)態(tài)變化,這樣的屬性叫狀態(tài),這類(lèi)對(duì)象也叫做有狀態(tài)的對(duì)象。當(dāng)此類(lèi)對(duì)象被某一事件修改其內(nèi)部狀態(tài)時(shí),程序的行為也要隨之改變

狀態(tài)模式又稱(chēng)狀態(tài)對(duì)象模式(Pattern of Objects for States)是用于解決對(duì)象的復(fù)雜狀態(tài)及不同狀態(tài)下的行為的一種模式。

模式定義

狀態(tài)模式允許一個(gè)對(duì)象在其內(nèi)部屬性改變的時(shí)候改變其行為,這個(gè)對(duì)象看上去就像是改變了它的類(lèi)一樣

模式結(jié)構(gòu)

狀態(tài)模式涉及角色:

  • 環(huán)境角色(Context):定義客戶(hù)感興趣的接口,并保留一個(gè)具體狀態(tài)類(lèi)的實(shí)例
  • 抽象狀態(tài)角色(State):定義一個(gè)借口,封裝特定狀態(tài)下的對(duì)應(yīng)行為
  • 具體狀態(tài)角色(ConcreteState):抽象狀態(tài)角色的子類(lèi),每個(gè)子類(lèi)實(shí)現(xiàn)了相關(guān)的行為

Tip:

  • 該圖為UML圖
  • 類(lèi)包含3個(gè)組成部分,第一欄為類(lèi)名,第二欄為屬性,第三欄為方法
  • 屬性和方法前可加一個(gè)可見(jiàn)性修飾符, + 號(hào)表示 public 修飾符, - 號(hào)表示 private 修飾符, # 號(hào)表示 protected 修飾符,省略表示包級(jí)可見(jiàn)。
  • 接口包含2個(gè)組成部分,第一欄為接口名,第二欄為方法,在接口名之上加上 <<interface>>

使用場(chǎng)景

比如游戲中一個(gè)用戶(hù)的用過(guò)外掛違規(guī)次數(shù)屬性,如果用戶(hù)用過(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ī)用戶(hù)及次數(shù)
    private Map<String, Integer> mPunishMap = new HashMap<>();


    /**
     * 獲取違規(guī)用戶(hù)及次數(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 用戶(hù)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            用戶(hù)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)");
    }
}

入口類(lèi)

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ú)類(lèi)中,方便增加新的狀態(tài),只需改變對(duì)象狀態(tài)即可改變對(duì)象行為

缺點(diǎn)

  • 增加了類(lèi)和對(duì)象的個(gè)數(shù)
  • 狀態(tài)模式對(duì)“開(kāi)閉原則”的支持并不太好,對(duì)于可以切換狀態(tài)的狀態(tài)模式,增加新的狀態(tài)類(lèi)需要修改那些負(fù)責(zé)狀態(tài)轉(zhuǎn)換的源代碼,否則無(wú)法切換到新增狀態(tài);而且修改某個(gè)狀態(tài)類(lèi)的行為也需修改對(duì)應(yīng)類(lèi)的源代碼。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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