程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#基礎知識 >> 狀態模式

狀態模式

編輯:C#基礎知識

需求:訂單有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("訂單已完成");
            }
        }
    }
}

雖然這種寫法看起來好像多出來許多類和代碼,但事實上業務邏輯的體現和代碼邏輯都會更清晰,對於維護和拓展來說也更加容易!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved