我們先來假設乙個業務場景來引入狀態模式以便於更好的理解,以後的設計模式系列我都會以這樣的方式來寫。
我們在**購買商品時,商品會依次出現以下狀態:等待買家付款,買家已付款,送貨中,交易成功。每個狀態可以做的操作如下:
等待買家付款:付款(為了讓整個流程可以走下去我們就忽略取消訂單吧...);
買家已付款:退貨;
送貨中:退貨,檢視物流資訊,確認收貨;
交易成功:退貨,檢視物流資訊,評價,再來一單;
退貨成功:再來一單。
在這個場景下有很多顯而易見的業務規則例如,商品狀態是等待買家付款時是不能進行退貨、檢視物流資訊、確認收貨和評價操作的(事實上**也不會給你這些選項);商品狀態是買家已付款時不能做付款、檢視物流資訊、確認收貨和評價操作等等。這些業務規則用if...else實現的效果是這樣的:
public void 付款() else
}public void 退貨() else if("退貨成功".equals(state)) else
public void 檢視物流() else
}public void 評價() else
}public void 再來一單() else
}
我用手都敲酸了...那如果有10個狀態呢?業務規則再複雜一些呢?用if...else耦合度太高,每次增加或修改乙個狀態或者業務規則就要修改每個方法的判斷。並且隨著業務複雜程度的提高,**維護愈發困難。這種情況下,我們使用狀態模式解決此業務場景更合適。
狀態模式即物件的內部狀態改變時改變它的行為,看起來好像改變了它的類。狀態模式是行為型模式的一種,後續我會介紹更多的行為型模式和其他型別的設計模式。
從類圖中我們可以看出狀態模式中有三類角色,分別是:
context:環境角色,即擁有各個狀態的物件;
state:抽象狀態介面角色,定義了context物件擁有的全部狀態的行為集合;
concretestate:具體狀態角色,對具體的狀態定義了具體的行為。
只看類圖可能對狀態模式的實現還不是這麼的了解,我們把上面的例子代入類圖各個角色就好理解一些。環境角色是擁有一系列狀態的物件,在本例中也就是商品;抽象狀態介面因為是抽象的並不對應任何物件;具體狀態角色就包括了等待買家付款、買家已付款、送貨中、交易成功和退貨成功。
為了避免使用上面用if...else實現的高耦合的**,商品物件便不能關心每乙個狀態的轉換具體是怎麼進行的,它應該只關心自己的當前狀態(即儲存當前狀態的引用),狀態間的轉換交給具體狀態角色去完成(具體狀態角色知道與自己有關的狀態轉換過程)。
抽象狀態介面:
abstract class goodsstate
//買家提交訂單,商品狀態變為「等待買家付款」
void submit(){};
//買家付款,商品狀態變為「買家已付款」
void payment(){};
//賣家發貨,商品狀態變為「送貨中」
void deliver(){};
//買家收貨,商品狀態變為「交易成功」
void receive(){};
//買家退貨,商品狀態變為「退貨成功」
void giveback(){};
}
商品狀態類
class goods
public void submit()
public void payment()
public void deliver()
public void receive()
public void giveback()
public void setcurrentstate(goodsstate currentstate)
public goodsstate getcurrentstate()
}
:
//等待買家付款
class waitingforpayment extends goodsstate
@override
public void payment()
@override
public void deliver()
@override
public void receive()
@override
public void giveback()
}//買家已付款
class paid extends goodsstate
@override
public void payment()
@override
public void deliver()
@override
public void receive()
@override
public void giveback()
}//送貨中
class delivering extends goodsstate
@override
public void payment()
@override
public void deliver()
@override
public void receive()
@override
public void giveback()
}//交易成功
class successfultrade extends goodsstate
@override
public void payment()
@override
public void deliver()
@override
public void receive()
@override
public void giveback()
}//退貨成功
class successfulreturn extends goodsstate
@override
public void payment()
@override
public void deliver()
@override
public void receive()
@override
public void giveback()
}
商品類:
class goods
public void submit()
public void payment()
public void deliver()
public void receive()
public void giveback()
public void setcurrentstate(goodsstate currentstate)
public goodsstate getcurrentstate()
}
測試類:
public static void main(string args)
輸出結果:
買家提交了訂單,當前狀態為:等待買家付款!
付款成功啦,等著賣家發貨吧!
還要再來一件麼老哥?
你還沒付錢呢你退個鬼哦?
賣家發貨咯!
你已經付過錢了呀老哥?
交易成功啦!
你都收到了還讓賣家發貨呢?
老哥,退貨成功了!
雖然我冥思苦想了很久還是寫出乙個不是很完美的例子,但是作用還是達到了。這裡需要注意的是在最開始設定狀態和每次修改狀態時我們都需要將當前商品物件傳給商品狀態物件,不然會出現空指標異常,同樣,在商品類裡每個狀態都要初始化。
通過以上我們可以看到使用狀態模式避免了使用過多的if...else判斷,使**耦合度大幅度降低。但類的數目會隨著狀態數量的增加而增加,因此還需謹慎使用。
如果從這篇文章看過之前提到的一些設計原則可以發現狀態模式符合幾條設計原則,事實上每個設計模式都起碼滿足一條設計原則,其中最多的還是面向介面程式設計,讀者可以在後續設計模式系列文章裡留意。
最後,前幾天加班有點嚴重,又因為無限火力開了所以這篇文章延後到現在才寫完,真是慚愧。
引以為戒。
設計模式之狀態模式
一 作用 允許乙個物件在其內部狀態改變時改變它的行為,物件看起來似乎修改了它的類。其別名為狀態物件 objects for states 狀態模式是一種物件行為型模式。二 例子 狀態抽象類 abstract class state 具體狀態類,每個狀態對應乙個類 class concretestat...
設計模式之 狀態模式
gof 設計模式 中給狀態模式下的定義為 允許乙個物件在其內部狀態改變時改變它 的行為。這個物件看起來似乎修改了它的類。看起來,狀態模式好像是神通廣大 居然能夠 修改自身的類 能夠讓程式根據不同的外部情況來做出不同的響應,最直接的方法就是在程式中將這些可能發生的外部情況全部考慮到,使用 if els...
設計模式之狀態模式
定義 允許乙個物件在其內部狀態變化時改變它的行為,物件看起來似乎修改了它所屬的類。類圖 說明 context表示環境類,它定義了客戶應用程式感興趣的介面,並維護乙個concretestate子類的例項,這個例項用於定義當前狀態 state表示抽象狀態類,它定義了乙個介面以封裝與context的乙個特...