設計模式之狀態模式

1、定義

你是否常常請()假()?是否是對公司萬惡的請假申請流程深痛絕。有沒有想過偷偷改造這個萬惡的系統,從 申請->項目經理審批->部門審批->老闆審批->完成  偷偷改成  申請->完成。爲了實現這個正義[偷笑]又合理的訴求,你得先學會今天要介紹的設計模式,由於大家公司的這個流程可能就是用今天這個模式設計的。來看看這個設計模式是怎麼來抽象這類流程性的業務的。面試

狀態模式【百度百科】:當一個對象的內在狀態改變時容許改變其行爲,這個對象看起來像是改變了其類。設計模式

這個定義看起來莫名其妙,咋一看,我也不知道它要表達什麼。我的的理解:某個對象是有狀態的,好比咱們上面的請假流程,它處於項目經理狀態,那項目經理能夠審覈你的請假申請,到了老闆處理環節,老闆直接把你申請單刪了【 哈哈】。在這不一樣的狀態是能夠有不一樣的操做的。

不知道你看懂了定義了沒??什麼?沒看懂,那就直接看下面的代碼咯,talk is cheap show me the code。
bash

2、UML圖

UML圖以下,我直接把請假這個例子畫了個UML圖,以下,有一個公共的State抽象類,裏面定義了兩個變量來保存當前狀態的狀態Code,狀態Name,下面爲具體的狀態,分別爲:AppState(申請狀態),ProjectManagesState(項目經理審覈狀態),BossState(老闆審覈狀態),經過Context來提供給客戶端使用。ide


3、請假流程實現

具體代碼實現以下:測試

一、狀態抽象類ui

package com.design.state;

public abstract class State {

    private String stateCode;
    private String stateName;
    //往下個環節走
    public abstract void toNextState(Context context);

    public State(String stateCode, String stateName){
        this.stateCode = stateCode;
        this.stateName = stateName;
    }

    public String getStateCode() {
        return stateCode;
    }

    public void setStateCode(String stateCode) {
        this.stateCode = stateCode;
    }

    public String getStateName() {
        return stateName;
    }

    public void setStateName(String stateName) {
        this.stateName = stateName;
    }
}
複製代碼

二、定義具體的狀態this

package com.design.state;

/**
 * 申請狀態
 */
public class AppState extends State{

    public AppState(){
        super("Apply", "申請環節");
    }

    @Override
    public void toNextState(Context context) {
        //申請狀態,這裏能夠作該狀態下的操做
        System.out.println("我是申請人,我申請休假,下一個環節是項目經理審覈!!");
        //直接進去項目經理審覈狀態
        context.setCurrentState(new ProjectManagesState());
    }
}
複製代碼


package com.design.state;

/**
 * 項目經理審覈狀態
 */
public class ProjectManagesState extends State{

    public ProjectManagesState(){
        super("ProjectManages", "項目經理審覈環節");
    }
    @Override
    public void toNextState(Context context) {
        //項目經理審覈狀態,這裏能夠作該狀態下的操作        
        System.out.println("我是項目經理,那臭小子必定有跑去面試了,哎,幫他一把,贊成了,下個環節讓老闆審去");
        //直接進去老闆審覈狀態
        context.setCurrentState(new BossState());
    }
}
複製代碼


package com.design.state;

/**
 * 老闆審覈狀態
 */
public class BossState extends State{

    public BossState(){
        super("Boss Audit", "老闆審覈環節");
    }

    @Override
    public void toNextState(Context context) {
        //項目經理審覈狀態,這裏能夠作該狀態下的操作
        System.out.println("我是老闆,我贊成你請假了!!!流程結束!");
    }

}
複製代碼

三、上下文類spa

package com.design.state;

public class Context {

    private State currentState;

    public Context(State state){
        currentState = state;
    }

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

    public State getCurrentState() {
        return currentState;
    }

    public void setCurrentState(State currentState) {
        this.currentState = currentState;
    }
}
複製代碼

四、寫好了,看下怎麼調用設計

package com.design.state;

public class TestMain {

    public static void main(String[] args) {
        //建立申請休假單
        Context context = new Context(new AppState());
        System.out.println("狀態:"+context.getCurrentState().getStateName());
        //提交申請
        context.toNextState();
        System.out.println("狀態:"+context.getCurrentState().getStateName());
        //項目經理審覈
        context.toNextState();
        System.out.println("狀態:"+context.getCurrentState().getStateName());
        //老闆審覈
        context.toNextState();
    }
}複製代碼

五、執行結果code


5、優缺點

一、優勢

(1)、將與特定狀態相關的行爲局部化,將不一樣狀態的行爲分割開來。

(2)、把狀態轉移邏輯分佈到具體狀態類中,減小相互間的依賴。

看不懂這兩個優勢??OK,咱們來解釋下,先來看看,不用狀態模式,咱們代碼會怎麼寫?

package com.design.state;

public class StateChange {
    private int state = 0;

    private final static int APPLY=0; //申請狀態
    private final static int PROJECTMANAGES=1;//項目經理審覈狀態
    private final static int BOSS=2;//老闆審覈狀態
    private final static int FINISH=3;//流程結束狀態

    public void toNextState(){
       switch (state){
           case 0:
               //申請狀態,作點操做
               System.out.println("寫申請書!!!");
               //進入項目經理審覈狀態
               state = PROJECTMANAGES;
               break;
           case 1:
               System.out.println("項目經理審覈,贊成你申請了");
               //進入老闆審覈狀態
               state = BOSS;
               break;
           case 2:
               System.out.println("我是老闆,贊成你申請了");
               //進入結束狀態
               state = FINISH;
               break;
           default:
               break;
       }
    }

}複製代碼

你是否是寫的跟我同樣呢??有沒有注意到,全部的操做,不管是哪一個狀態的操做都是在這個類中完成的,而使用狀態模式,不一樣狀態下的行爲是定義在不一樣的狀態類下的。這就是前面說的優勢1。

咱們狀態切換是經過switch來判斷狀態,再決定下一個狀態的,而在狀態模式下,切換到下一個狀態,是在具體的狀態類下進行的,能夠減小if之類的判斷邏輯。這就是優勢2。

二、缺點

(1)、狀態模式的結構與實現都較爲複雜,若是使用不當將致使程序結構和代碼的混亂。 

(2)、狀態模式對"開閉原則"的支持並不太好,新增狀態時,不只得增長狀態類,還得修改原來已經有的狀態,讓以前的狀態切換到新增的狀態。

6、總結說明

狀態模式將原來經過判斷實現的狀態切換分散到各具體狀態類中,好比上面切換到「老闆審覈狀態」,是在「項目經理審覈狀態」中進行的,當狀態比較多的狀況,不容易理清各狀態切換關係。同時它有將各狀態的操做獨立到狀態類中,方便測試,還有分隔開各不一樣操做,便於閱讀代碼。實際運用中可根據本身的場景進行權衡。

相關文章
相關標籤/搜索