你是否常常請(偷)假(懶)?是否是對公司萬惡的請假申請流程深惡痛絕。有沒有想過偷偷改造這個萬惡的系統,從 申請->項目經理審批->部門審批->老闆審批->完成 偷偷改成 申請->完成。爲了實現這個正義[偷笑]又合理的訴求,你得先學會今天要介紹的設計模式,由於大家公司的這個流程可能就是用今天這個模式設計的。來看看這個設計模式是怎麼來抽象這類流程性的業務的。面試
狀態模式【百度百科】:當一個對象的內在狀態改變時容許改變其行爲,這個對象看起來像是改變了其類。設計模式
這個定義看起來莫名其妙,咋一看,我也不知道它要表達什麼。我的的理解:某個對象是有狀態的,好比咱們上面的請假流程,它處於項目經理狀態,那項目經理能夠審覈你的請假申請,到了老闆處理環節,老闆直接把你申請單刪了【 哈哈】。在這不一樣的狀態是能夠有不一樣的操做的。不知道你看懂了定義了沒??什麼?沒看懂,那就直接看下面的代碼咯,talk is cheap show me the code。
bash
UML圖以下,我直接把請假這個例子畫了個UML圖,以下,有一個公共的State抽象類,裏面定義了兩個變量來保存當前狀態的狀態Code,狀態Name,下面爲具體的狀態,分別爲:AppState(申請狀態),ProjectManagesState(項目經理審覈狀態),BossState(老闆審覈狀態),經過Context來提供給客戶端使用。ide
具體代碼實現以下:測試
一、狀態抽象類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
(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)、狀態模式對"開閉原則"的支持並不太好,新增狀態時,不只得增長狀態類,還得修改原來已經有的狀態,讓以前的狀態切換到新增的狀態。
狀態模式將原來經過判斷實現的狀態切換分散到各具體狀態類中,好比上面切換到「老闆審覈狀態」,是在「項目經理審覈狀態」中進行的,當狀態比較多的狀況,不容易理清各狀態切換關係。同時它有將各狀態的操做獨立到狀態類中,方便測試,還有分隔開各不一樣操做,便於閱讀代碼。實際運用中可根據本身的場景進行權衡。