從零開始學設計模式(十八):狀態模式(State Pattern)
作者的其他平臺:
| CSDN:blog.csdn.net/qq\_4115394…
| 掘金:juejin.cn/user/651387…
| 知乎:www.zhihu.com/people/1024…
| GitHub:github.com/JiangXia-10…
| 公眾號:1024筆記
本文大概3474字,讀完預計需要9分鐘
定義
狀態模式(State Pattern)指的是將一個物件的狀態從該物件中分離出來,封裝到專門的狀態類中,使得物件狀態可以靈活變化,在其內部狀態改變時改變它的行為。狀態模式是一種物件行為型模式。它和策略模式有一點很像,就是將一些複雜的邏輯放在一個專門的上下文類中進行處理。
往往在一個系統中的某個物件會存在多個狀態,而且這些狀態之間可以進行轉換,並且在不同的狀態下會具有不同的行為或者功能,比如很多喜歡看電視的朋友有時候用騰訊視訊看電視,如果不充值會員的話,會有廣告,而且很多vip的節目也不能觀看了,衝了會員就沒了廣告,而且也能解鎖vip節目,這時候使用者就擁有兩個狀態,一個是vip狀態,一個是非vip狀態,而且在不同的狀態下也有不同的行為,這時候的系統設計就可以使用狀態模式。
組成部分
狀態模式包含以下三個主要部分:
1、抽象狀態類(State):它主要定義了一個公共介面或者抽象方法,用以封裝環境物件中的特定狀態所對應的行為,可以有一個或多個行為。
2、具體狀態類(Concrete State):它主要就是繼承或者實現抽象狀態類/介面,並且實現抽象狀態所對應的行為,在需要的情況下進行狀態切換。
3、環境類(Context):也叫上下文,它內部維護一個當前狀態,並負責具體狀態的切換,最終給客戶端呼叫。
例子
首先定義一個抽象的狀態類,並且有抽象的行為方法:
public abstract class State { public abstract void Do(); }
接著定義兩個具體的狀態子類去繼承抽象的狀態類,並且實現抽象方法:
public class ConcreteState1 extends State { @Override public void Do() { System.out.println("吃跑了,來外面散散步"); } } public class ConcreteState2 extends State { @Override public void Do() { System.out.println("肚子很餓,需要吃飯"); } }
接著定義一個上下文類,即環境類,用來處理狀態和行為:
public class Context {
// 維護一個抽象狀態物件的引用
private State state;
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public boolean isHungry() {
return isHungry;
}
public void setHungry(boolean hungry) {
isHungry = hungry;
}
private boolean isHungry;
private void checkStates(){
if(isHungry){
//如果餓了的狀態需要做飯
setState(new ConcreteState2());
}else{
//吃飽了,出去走走
setState(new ConcreteState1());
}
}
public void process(){
checkStates();
state.Do();
}
}
測試方法:
public class StatePatternTest {
public static void main(String[] args) {
Context context = new Context();
//設定狀態為餓了
context.setHungry(true);
context.process();
//設定狀態為不餓
context.setHungry(false);
context.process();
}
}
執行結果:
上面狀態的處理,切換改變,除了可以在上下文類中實現,還可以在具體的狀態子類中實現,比如:
首先需要在上下文類中初始化一個狀態例項物件,並且將上下文物件作為子類的狀態的構造引數傳遞給具體的子類中,上下文類程式碼:
// 設定初始狀態
this.state = new ConcreteStateA(this);
然後在具體的子類狀態類中根據構造進來的上下文類例項物件,通過呼叫它的屬性值進行業務邏輯判斷 進行狀態的檢查和切換。比如在ConcreteState1類的程式碼修改如下:
public class ConcreteState3 extends State {
private Context context;
public ConcreteState3(Context context){
context= context;
}
@Override
public void Do() {
System.out.println("吃跑了,來外面散散步");
checkState();
}
/**
* 檢查狀態 是否需要進行狀態的轉換<br/>
* 狀態的切換由具體狀態子類中實現 */
private void checkState(){
if (context.getisHungry()) {
context.setState(new ConcreteState1(context));
}
}
}
狀態模式的優點
1、狀態模式的程式碼結構清晰,它將與特定狀態相關的行為區域性化到一個狀態中,並且將不同狀態的行為分割開來,體現了“單一職責原則”。
2、將不同的狀態引入獨立的物件中會使得狀態轉換變得更加明確,且減少物件間的相互依賴。
3、每個具體的狀態類負責具體的職責,有利於程式的擴充套件。可以增加新的子類來增加新的狀態和行為。
狀態模式的缺點
1、同狀態模式的第三個優點,拓展的同時會增加程式碼量,每增加一個新的子類,都會增加程式碼中類的個數;
2、狀態模式符合單一職責原則,但是對“開閉原則”的支援並不太好,增加新的狀態類需要修改那些負責狀態轉換的原始碼,否則無法切換到新增狀態;而且修改某個狀態類的行為也需修改對應類的原始碼。
應用場景
1、物件的行為依賴於它的狀態並且可以根據它的狀態改變而改變它的相關行為,比如前面說的會員系統;
2、一個操作中含有龐大的分支結構,並且這些分支決定於物件的狀態時。比如常見的if else結構的程式碼,或者switch語句等等。
總結
狀態模式總結起來是如果一個物件的行為依賴於狀態或者屬性,那麼可以將狀態和行為拆分封裝在一個環境類中處理,然後具體的子類負責具體行為。
最後本文以及之前的所有的設計模式中的例子程式碼,都將同步至github,需要的歡迎下載star。
Github地址:
相關推薦:
從零開始學設計模式(三):原型模式(Prototype Pattern)
從零開始學設計模式(四):工廠模式(Factory Pattern)
從零開始學設計模式(五):建造者模式(Builder Pattern)
從零開始學設計模式(六):介面卡模式(Adapter Pattern)
從零開始學設計模式(六):代理模式(Proxy Pattern)
從零開始學設計模式(八):裝飾器模式(Decorator Pattern)
從零開始學設計模式(九):外觀模式(Facade Pattern)
從零開始學設計模式(十):橋接模式(Bridge Pattern)
從零開始學設計模式(十一):組合模式(Composite Pattern)
從零開始學設計模式(十二):享元模式(Flyweight Pattern)
從零開始學設計模式(十三):訪問者模式(Visitor Pattern)
從零開始學設計模式(十四):中介者模式(Mediator Pattern)
從零開始學設計模式(十五):模版方法模式(Template Method Pattern)