設計模式之狀態模式

定義

Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.(當一個對象內在狀態改變時容許其改變行爲,這個對象看起來像改變了其類。)app

UML類圖

角色解釋

  • Context,環境,封裝各類狀態的變化,而且向外部提供全部須要的接口,使得外部不用關注狀態的變化,只須要關注抽象的行爲,以及初始狀態。
  • State,狀態,抽象全部狀態的行爲,而且依賴Context,提供setContext方法。
  • ConcreateState,狀態實現,總結下就是每一個狀態只關注本身的行爲實現,針對不屬於本身的行爲能夠進行拋錯。

代碼示例

已開門狀態和關門狀態舉例:ide

Context類:this

public class DoorContext {
    public static final DoorState OPEN_STATE = new OpenState();
    public static final DoorState CLOSE_STATE = new CloseState();
    /**
     * 當前狀態
     */
    private DoorState currentState;

    /**
     * 得到當前狀態
     */
    public DoorState getCurrentState() {
        return currentState;
    }

    public void setCurrentState(DoorState doorState) {
        doorState.setDoorContext(this);
        this.currentState = doorState;
    }

    public void close() {
        this.currentState.close();
    }

    public void open() {
        this.currentState.open();
    }

    public void enter() {
        this.currentState.enter();
    }

    public void out() {
        this.currentState.out();
    }

    public void knock() {
        this.currentState.knock();
    }
}

State抽象類:code

public abstract class DoorState {
    protected DoorContext doorContext;

    public void setDoorContext(DoorContext _Door_context) {
        this.doorContext = _Door_context;
    }

    public abstract void open();

    public abstract void close();

    public abstract void enter();

    public abstract void out();

    public abstract void knock();

}

關門狀態實現類:對象

@Override
    public void open() {
        System.out.println("開門");
        //切換狀態
        super.doorContext.setCurrentState(DoorContext.OPEN_STATE);
    }


    @Override
    public void close() {
        System.out.println("已關門");
    }


    @Override
    public void knock() {
        System.out.println("關着的門用力敲");
    }


    @Override
    public void enter() {
        throw new RuntimeException("門關了,進門失敗");
    }

    @Override
    public void out() {
        throw new RuntimeException("門關了,出門失敗");
    }

開門狀態實現類:blog

public class OpenState extends DoorState {
    @Override
    public void enter() {
        System.out.println("進入");
    }

    @Override
    public void out() {
        System.out.println("出來");
    }

    @Override
    public void knock() {
        System.out.println("開着的門輕輕敲");
    }

    @Override
    public void open() {
        System.out.println("門已經開着了");
    }

    /**
     * 涉及到切換到其餘狀態
     */
    @Override
    public void close() {
        System.out.println("關門");
        super.doorContext.setCurrentState(DoorContext.CLOSE_STATE);
    }
}

場景類1:接口

public static void main(String[] args) {
        DoorContext doorContext = new DoorContext();
        //給個初始狀態
        doorContext.setCurrentState(DoorContext.CLOSE_STATE);
        //敲門
        doorContext.knock();
        //開門
        doorContext.open();
        //進門
        doorContext.enter();
        //關門
        doorContext.close();
        //進門
        doorContext.open();
        //出門
        doorContext.out();
        //關門
        doorContext.close();
    }

觀察場景類能夠知道,當場景類調用的時候,根本不須要在乎狀態,只須要關注須要實現的行爲,而具體能不能實現行爲,具體怎麼實現這個行爲,狀態的流轉,則被封裝在了Context裏。get

應用場景

  • 行爲與狀態有相互依賴的關係。 也就是說,行爲受狀態影響(狀態會改變行爲),而狀態也受行爲影響(行爲會改變狀態),狀態模式就是將每一個狀態抽出來,而後針對每一個行爲進行實現,遇到切換狀態的行爲的時候將當前場景Context裏面的狀態切換就好了。而對於Context來講,只須要將外部的調用轉發個當前場景內部的狀態去處理就好了。

優勢

  • 屏蔽了狀態切換,而且又擁有良好的健壯性,沒有忽視行爲受狀態的影響,只是封裝在了狀態內部去去處理了。
  • 符合單一職責,若是不該用狀態模式,那麼狀態和行爲是耦合在一個類中,不符合單一職責原則。
  • 符合開閉原則,高層模塊不關注具體狀態實現,若是須要擴展狀態,只須要在底層添加一個狀態實現類就是了。