需求:訂單有5個狀態(新訂單、已付款、已發貨、已完成、已取消)
正常狀態轉換:新訂單-》已付款-》已發貨-》已完成
除了已完成,其它都是可以取消的
已完成 、已取消:啥也不能做
對於這樣子的一個需求,似乎代碼很快就能給出,好,先看第一版
第一版:
using System;
namespace DP.Observer.V4
{
public class Order
{
public const int StatusNew = 1;
public const int StatusPaid = 2;
public const int StatusShipped = 3;
public const int StatusComplete = 4;
public const int StatusCancel = 0;
private int _orderStatus;
public string OrderCode { get; set; }
public string UserName { get; set; }
public int OrderStatus
{
get { return _orderStatus; }
}
public Order(string userName, string orderCode, int orderStatus)
{
UserName = userName;
OrderCode = orderCode;
_orderStatus = orderStatus;
}
public void Pay()
{
if (_orderStatus == StatusNew)
{
_orderStatus = StatusPaid;
//do something
Console.WriteLine("付款啦");
}
}
public void Ship()
{
if (_orderStatus == StatusPaid)
{
_orderStatus = StatusShipped;
Console.WriteLine("發貨啦");
}
}
public void Complete()
{
if (_orderStatus == StatusShipped)
{
_orderStatus = StatusComplete;
Console.WriteLine("訂單已完成");
}
}
public void Cancel()
{
if (_orderStatus == StatusNew || _orderStatus == StatusPaid || _orderStatus == StatusShipped)
{
_orderStatus = StatusCancel;
Console.WriteLine("訂單已取消");
}
Console.WriteLine("當前訂單狀態不能被取消");
}
}
}
如果需求不會變化,似乎這樣寫沒有任何問題
然而不幸的事情還是發生了,有一天老板就同我講,其實我們的訂單流程不僅僅是這樣的,也有可能是先發貨,完了收到貨再付款
那麼現在訂單的狀態轉換就有了兩種流程,這裡姑且把第一種叫做 ‘現款支付’,後者叫做 ‘貨到付款’
好,接下來就動手改代碼吧!
如果不知道狀態模式,我可能會這樣寫,首先給訂單加個類型標識它是 ‘現款支付’ 還是 ‘貨到付款’,然後
public const int TypeFirstPay = 1;
public const int TypeFirstShip = 2;
private int _orderType;
public int OrderType
{
get { return _orderType; }
}
public void Pay()
{
if (_orderType == TypeFirstPay)
{
if (_orderStatus == StatusNew)
{
_orderStatus = StatusPaid;
//do something
Console.WriteLine("付款啦");
}
}
else if (_orderType == TypeFirstShip)
{
if (_orderStatus == StatusPaid)
{
_orderStatus = StatusPaid;
//do something
Console.WriteLine("付款啦");
}
}
}
這裡僅僅以 pay() 方法做一個示例
實際上,這種寫法是很難維護和拓展的,舉個簡單的例子,訂單的類型可能不止兩個,而且訂單的狀態和流程也可能會變動,面對這種情況那些 if else 就足以讓人頭疼了
好,現在嘗試用狀態模式來改進這種 if else 的寫法,顯而易見的一點是,這裡訂單狀態的轉換流程是由 OrderType 決定的,所以在這裡 OrderType 才是狀態模式裡的狀態,並不是指訂單狀態哦!
(題外話,其實訂單狀態也可以寫狀態模式,之前的例子就是用訂單狀態寫的,但完了覺得沒有太大實際意義,純粹只是為了實現一個狀態模式,所以改用一個實際項目中遇到過的問題,就是這個訂單類型 OrderType)
訂單類:
using System;
namespace DP.Observer.V5
{
public class Order
{
public const int StatusNew = 1;
public const int StatusPaid = 2;
public const int StatusShipped = 3;
public const int StatusComplete = 4;
public const int StatusCancel = 0;
public const int TypeFirstPay = 1;
public const int TypeFirstShip = 2;
private OrderType.OrderType _orderType;
public string OrderCode { get; set; }
public string UserName { get; set; }
public int OrderStatus { get; set; }
public int OrderType
{
get { return _orderType.GetOrderType(); }
set
{
switch (value)
{
case TypeFirstPay:
_orderType = new OrderType.FirstPay();
break;
case TypeFirstShip:
_orderType = new OrderType.FirstShip();
break;
default: throw new Exception("error orderType");
}
}
}
public Order(string userName, string orderCode, int orderStatus, int orderType)
{
UserName = userName;
OrderCode = orderCode;
OrderStatus = orderStatus;
OrderType = orderType;
}
public void Pay()
{
_orderType.Pay(this);
}
public void Ship()
{
_orderType.Ship(this);
}
public void Complete()
{
_orderType.Complete(this);
}
public void Cancel()
{
_orderType.Cancel(this);
}
}
}
狀態-父類:
using System;
namespace DP.Observer.V5.OrderType
{
public abstract class OrderType
{
public abstract int GetOrderType();
public abstract void Pay(Order order);
public abstract void Ship(Order order);
public abstract void Complete(Order order);
public virtual void Cancel(Order order)
{
{
if (order.OrderStatus == Order.StatusNew ||
order.OrderStatus == Order.StatusPaid ||
order.OrderStatus == Order.StatusShipped)
{
order.OrderStatus = Order.StatusCancel;
Console.WriteLine("訂單已取消");
}
}
}
}
}
狀態1:
using System;
namespace DP.Observer.V5.OrderType
{
public class FirstPay : OrderType
{
public override int GetOrderType()
{
return Order.TypeFirstPay;
}
public override void Pay(Order order)
{
if (order.OrderStatus == Order.StatusNew)
{
order.OrderStatus = Order.StatusPaid;
Console.WriteLine("付款啦");
}
}
public override void Ship(Order order)
{
if (order.OrderStatus == Order.StatusPaid)
{
order.OrderStatus = Order.StatusShipped;
Console.WriteLine("發貨啦");
}
}
public override void Complete(Order order)
{
if (order.OrderStatus == Order.StatusShipped)
{
order.OrderStatus = Order.StatusComplete;
Console.WriteLine("訂單已完成");
}
}
}
}
狀態2:
using System;
namespace DP.Observer.V5.OrderType
{
public class FirstShip : OrderType
{
public override int GetOrderType()
{
return Order.TypeFirstShip;
}
public override void Ship(Order order)
{
if (order.OrderStatus == Order.StatusNew)
{
order.OrderStatus = Order.StatusShipped;
Console.WriteLine("發貨啦");
}
}
public override void Pay(Order order)
{
if (order.OrderStatus == Order.StatusShipped)
{
order.OrderStatus = Order.StatusPaid;
Console.WriteLine("付款啦");
}
}
public override void Complete(Order order)
{
if (order.OrderStatus == Order.StatusPaid)
{
order.OrderStatus = Order.StatusComplete;
Console.WriteLine("訂單已完成");
}
}
}
}
雖然這種寫法看起來好像多出來許多類和代碼,但事實上業務邏輯的體現和代碼邏輯都會更清晰,對於維護和拓展來說也更加容易!