Go 代碼應用設計模式: 狀態模式、策略模式
我們繼續學習行爲模式中的狀態模式。
某個對象可能有很多的狀態,且伴隨着不同的狀態有着不同的行爲模式。而狀態模式正是用來處理多種狀態和行爲的關係的。
在電商系統的中,訂單有着非常多的狀態,而不同的狀態下訂單的行爲也是不同的。我們爲了簡化例子,假設訂單一共有以下四種狀態:
-
下單
-
已支付
-
出庫
-
已取消
而圍繞着訂單的狀態有以下行爲:
-
加購
-
支付
-
取消
我們還是從反例開始理解狀態模式。圍繞着這些裝的行爲,在我們的代碼中可能有着非常多的 if 或者 switch 語句來處理:
type Order struct {
orderID string
state int
}
const (
OrderAdded = 1
OrderPaied = 2
OrderSended = 3
OrderRefund = 4
)
func addOrder() Order {
return Order{
orderID: "xxx",
state: OrderAdded,
}
}
// 取消訂單
func (o *Order) refund() {
switch o.state {
case OrderAdded:
// todo ...
case OrderPaied:
// todo ...
case OrderSended:
// todo ...
case OrderRefund:
// todo ...
}
}
這裏只列舉出來了 refund 接口,需要根據訂單的不同狀態來做不同的處理。這裏我們的示例只是有 4 個狀態,而現實的電商系統狀態要多得多,這樣這個 switch 會特別的大(狀態多了,行爲也就更多,每個行爲中的 switch 都特別大),影響代碼閱讀。
我們來看看狀態模式如何處理以上邏輯呢?
type OrderAddedState struct {
order Order
}
type OrderPaiedState struct {
order Order
}
type OrderSendedState struct {
order Order
}
type OrderRefundState struct {
order Order
}
func (o *OrderAddedState) Refund() error {
//更新定單狀態爲已關閉
return nil
}
func (o *OrderPaiedState) Refund() error {
// 發起退款
//更新定單狀態爲已關閉
return nil
}
func (o *OrderSendedState) Refund() error {
// 取消發貨
// 發起退款
// 更新定單狀態爲已關閉
return nil
}
func (o *OrderRefundState) Refund() error {
return errors.New("order has been refunded")
}
我們可以看到在不同的狀態下的取消訂單,封裝到獨立的類中去了,同時不同狀態下的其他行爲也可保證一樣的處理,這樣在不同狀態下的行爲需要處理哪些邏輯將一目瞭然,而無序去讀很長且複雜的 siwtch 代碼。
接下來我們瞭解行爲模式中的策略模式。
策略模式可以使對象的行爲可以靈活的在多個算法之間切換。我們還是用電商這個實際案例來了解策略模式。假設商品的活動有直接折扣、加價購、套裝等銷售策略,如何在下單時計算這個商品的價格呢?
我們還是從反例來說明以上邏輯,通常我們還是會用多個 if else 來根據不同的銷售模式來計算商品的價格。且活動的優先級就已經通過 if 的層級進行劃分,而如果不同的商品活動優先級不同,又需要額外的 if 來進行判斷。從而使整個計算邏輯在多個且多層 if else 中處理,後期的維護越來越難。
我們看下策略模式是如何實現這個電商的實際場景的,首先我們定義計算邏輯的接口:
type orderAlgo struct {
}
type evictionAlgo interface {
evict(orderAlgo)
}
直接折扣、加價購、套裝等具體的算法類將實現這個接口:
type cutoff struct {
}
type addPrice struct {
}
type suit struct {
}
func (cutoff) calc(calcuInfo) {
fmt.Println("普通折扣計算")
}
func (addPrice) calc(calcuInfo) {
fmt.Println("加價購折扣計算")
}
func (suit) calc(calcuInfo) {
fmt.Println("套裝摺扣計算")
}
這樣每一個算法的邏輯在自己的成員函數中處理,而無需關注其他的計算邏輯,且不會像反例中一樣所有的計算邏輯柔和在一起。同時多個活動的優先級可由計算算法的調用先後次序決定。
但是這裏無法處理經過某個優惠後無法進行下一個優惠的實際場景,例如普通折扣後的商品無法再參與到套裝活動中,那麼需要調用方進行一系列的邏輯處理,例如給每種活動加上檢查函數,先檢查再調用。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/4ffqh5sBZgUpBii8mWUnxA