設計模式-狀態模式

定義

狀態模式(State),當一個對象的內部狀態改變時容許改變其行爲,這個對象看起來像是改變了其類。

類圖

cYqyRcVcaC4AAAAASUVORK5CYII=

  • Context:環境,上下文,其實就是狀態管理者,隱藏了狀態之間轉換的細節,是客戶端與各個狀態的中間人。request()方法是客戶端調用的,
  • State:抽象狀態,定義了狀態的處理抽象方法handle(),各個具體狀態須要實現它。
  • ConcreteState:具體狀態,實現了狀態的公共方法,且包含了狀態轉換的判斷。

經典源碼

狀態管理者架構

public class Context {
    //持有一個State類型的對象實例
    private State state;

    public void setState(State state) {
        this.state = state;
    }
    /**
     * 客戶端調用
     */
    public void request(String sampleParameter) {
        //轉調state來處理
        state.handle(sampleParameter);
    }
}

抽象狀態ide

public interface State {
    /**
     * 狀態對應的處理
     */
    public void handle(String sampleParameter);
}

具體狀態Athis

public class ConcreteStateA implements State {

    @Override
    public void handle(String sampleParameter) {
        
        System.out.println("ConcreteStateA handle :" + sampleParameter);
    }

}

具體狀態Bspa

public class ConcreteStateB implements State {

    @Override
    public void handle(String sampleParameter) {
        
        System.out.println("ConcreteStateB handle :" + sampleParameter);
    }

}
客戶端調用方
public class Client {

    public static void main(String[] args){
        //建立狀態
        State state = new ConcreteStateB();
        //建立環境
        Context context = new Context();
        //將狀態設置到環境中
        context.setState(state);
        //請求
        context.request("test");
    }
}

實際案例

背景

小A正在召喚師峽谷廝殺,他玩的是卡特,買了一本殺人書。隨着遊戲時間的進行,小A殺的人愈來愈多,且本身都沒死過,遊戲中不斷傳來「XXX暴走了」、「XXX主宰了比賽」、「XXX接近神了」。最終小A以12殺0死的完美戰績結束了比賽,腦海中剛纔的捷報聲還在不停環繞在他的耳邊,他就想這不就是狀態模式,隨後打開IDE開始復現剛纔的過程。code

結構

環境類orm

package com.jo.state;

/**
 * @author Jo
 * @date 2018/1/17
 */
public class LolContext {
    /**
     * 當前殺人狀態
     */
    private KillState killState;

    /**
     * 當前殺人數
     */
    private Integer killNum = 0;

    public LolContext() {
        killState = new Normal();
    }

    public Integer getKillNum() {
        return killNum;
    }

    public LolContext setKillState(KillState killState) {
        this.killState = killState;
        return this;
    }

    /**
     * 殺人方法,
     */
    public void kill(){
        killNum += 1;
        killState.kill(this);
        System.out.println("當前擊殺數" + killNum);
        System.out.println();
    }
}

抽象殺人狀態對象

public interface KillState {
    /**
     * 抽象殺人方法
     * @param lolContext
     */
    void kill(LolContext lolContext);
}

普通擊殺遊戲

public class Normal implements KillState {
    @Override
    public void kill(LolContext lolContext) {
        System.out.println("你殺了一我的");
        //殺了2我的的時候轉換狀態
        if (lolContext.getKillNum() > 1){
            lolContext.setKillState(new KillingSpring());
        }
    }
}

大殺特殺圖片

public class KillingSpring implements KillState {
    @Override
    public void kill(LolContext lolContext) {
        System.out.println("你正在大殺特殺");
        lolContext.setKillState(new Rampage());
    }
}

接近暴走get

public class Rampage implements KillState {
    @Override
    public void kill(LolContext lolContext) {
        System.out.println("你已經接近暴走了");
        lolContext.setKillState(new Unstoppable());
    }
}

無人可擋

public class Unstoppable implements KillState {
    @Override
    public void kill(LolContext lolContext) {
        System.out.println("你已經無人可擋了");
        lolContext.setKillState(new Dominating());
    }
}





超神

public class Legendary implements KillState {
    @Override
    public void kill(LolContext lolContext) {
        System.out.println("你已經超神了");
    }
}

客戶端調用

public class Client {
    public static void main(String[] args) {
        LolContext lolContext = new LolContext();
        for (int i = 0; i < 13; i++) {
            lolContext.kill();
        }
    }
}

運行結果
圖片描述

客戶端只負責調用LolContext的kill方法,其他一律不知,內部便會隨着殺人數的增加打印不一樣的通知。而LolContext中也沒有複雜,一大串的if else switch case,狀態的轉移在各自的具體狀態中,若是須要修改部分邏輯只須要改對應的狀態,而不須要改本來在一塊兒的if else,大大減小了隱患的發生率,從而不會發生牽一髮而動全身的結果。

適用場景

狀態模式的優勢是解除了程序的耦合度,採用子類的方式去除了煩瑣容易出錯的if else,但反而帶來的是類的數據增多。若是你要實現的功能狀態很少,且功能簡單,那不推薦使用狀態模式,否則會徒增程序的複雜性。且要執行的動做有必定的複雜度,此例的kill方法是最簡單的實現,實際應用中複雜度是遠遠大於它的。你能夠想象在狀態多,且複雜的動做中不使用狀態模式會事怎樣,if else多的眼花繚亂,上一個if和下一個else if相差幾百行代碼,想必這樣的代碼誰都不肯意碰,萬一改壞了就要背鍋了。

總結

狀態模式和和策略模式有點相像,狀態模式的狀態轉移是內部控制的,而策略模式是由客戶端控制採用不一樣的策略。所以在目的和實現仍是有很大的差異的。有些場景「狀態」不是那麼明顯,須要轉換成狀態模式就考察使用者的功底和對業務的理解程度了,望你們都能get更多知識點,能力愈來愈強,個個都是架構師。

相關文章
相關標籤/搜索