zoukankan      html  css  js  c++  java
  • State模式的经典应用场景:订单处理(c#实现)

    State模式在对象内部状态发生变化的时候,改变自身的行为,这通常是通过切换内部状态对象实现的,对象将自身在各个状态的行为推给了状态对象,从而解开了行为与对象的依赖。

    场景描述

    在经典的订单处理场景中,订单其不同状态的时候变现了不同的行为,具体内容如下:

    1. 假如订单是一个新创建的订单,那么它可以被寄送,也可以被取消;
    2. 假如订单已经被寄送,那么它不可以被再次寄送,也不可以被取消;
    3. 假如订单已经被取消,那么它不可以被寄送,也不可以被取消。

    上述内容中详细解释了订单状态和对应行为的关系。

    遇到问题

    对逻辑的第一映像,通常是通过if-else或者switch子句,通过订单内部的一个表示状态的属性,判断出当前订单是否可以寄送和取消。

    可是这样严重影响了程序代码的课扩展性,想想一下,如果我需要添加一种叫做“已出库”的状态,此时订单表现为可以被取消但是不可以再次申请寄送,那我们就需要在if-else子句中添加新的逻辑;又或者我们需要改变业务规则寄送的订单可以在没有完成前取消,那么我们又需要对订单的实现代码做逻辑更改,很明显,这样对扩展性来说是一个大问题。

    所以,我们的解决方案是将订单的行为推送到订单状态自身,这样即使扩展再多的订单状态或者对状态行为进行更改,也可以轻松应对,只对很少的类进行更改,并且不会牵涉到太多代码逻辑。

    解决问题走起

    首先创建一个订表示订单状态的枚举OrderStatus

    namespace Pattern.State
    {
    public enum OrderStatus
    {
    New=0,
    Shipped=1,
    Canceled=2
    }
    }

    然后创建一个借口IOrderState,定义订单的行为和保存订单的状态枚举值

    namespace Pattern.State
    {
    public interface IOrderState
    {
    bool CanShip(Order order);
    void Ship(Order order);
    bool CanCancel(Order order);
    void Cancel(Order order);
    OrderStatus Status { get; }
    }
    }

    接下来就是最重要的Order类

    namespace Pattern.State
    {
    public class Order
    {
    private IOrderState orderState;


    public Order(IOrderState orderState)
    {
    this.orderState = orderState;
    }


    public int Id { get; set; }
    public string CustomerName { get; set; }
    public string Address { get; set; }

    public OrderStatus Status()
    {
    return orderState.Status;
    }

    public bool CanCancel()
    {
    return orderState.CanCancel(this);
    }

    public void Cancel()
    {
    if (CanCancel())
    {
    orderState.Cancel(this);
    }
    }

    public bool CanShip()
    {
    return orderState.CanShip(this);
    }

    public void Ship()
    {
    if (CanShip())
    {
    orderState.Ship(this);
    }
    }

    internal void Change(IOrderState orderState)
    {
    this.orderState = orderState;
    }
    }
    }

    你可以看到,本来想象中的复杂了代码逻辑没有了,代码变得更易懂易扩展,因为我们将这些行为转到了IOrderState的子类中,单个子类只维护当前状态下订单的行为:

    1.NewState

    namespace Pattern.State
    {
    public class NewState:IOrderState
    {
    public bool CanShip(Order order)
    {
    //some logic here
    return true;
    }

    public void Ship(Order order)
    {
    order.Change(new ShippedState());
    }

    public bool CanCancel(Order order)
    {
    return true;
    }

    public void Cancel(Order order)
    {
    order.Change(new CanceledState());
    }

    public OrderStatus Status
    {
    get { return OrderStatus.New; }
    }
    }
    }

    2.ShippedState

    namespace Pattern.State
    {
    public class ShippedState:IOrderState
    {
    public bool CanShip(Order order)
    {
    return false;
    }

    public void Ship(Order order)
    {
    throw new InvalidOperationException();
    }

    public bool CanCancel(Order order)
    {
    return false;
    }

    public void Cancel(Order order)
    {
    throw new InvalidOperationException();
    }

    public OrderStatus Status
    {
    get { return OrderStatus.Shipped }
    }
    }
    }

    3.CanceledState

    namespace Pattern.State
    {
    public class CanceledState:IOrderState
    {
    public bool CanShip(Order order)
    {
    return false;
    }

    public void Ship(Order order)
    {
    throw new InvalidOperationException();
    }

    public bool CanCancel(Order order)
    {
    return false;
    }

    public void Cancel(Order order)
    {
    throw new InvalidOperationException();
    }

    public OrderStatus Status
    {
    get { return OrderStatus.Canceled; }
    }
    }
    }

    最后我们创建一个OrderFactory

    namespace Pattern.State
    {
    public static class OrderFactory
    {
    public static Order CreateOrder(string customerName, string address)
    {
    IOrderState orderState = new NewState();
    Order order = new Order(orderState);
    return order;
    }
    }
    }

    最后,通过一个控制台应用程序来测试一下:

    namespace Pattern.Console
    {
    class Program
    {
    static void Main(string[] args)
    {
    Order order = OrderFactory.CreateOrder("小白哥哥", "天津市和平区");
    if (order.CanShip())
    {
    System.Console.WriteLine("订单当前可以寄送");
    }
    order.Ship();
    if (!order.CanShip())
    {
    System.Console.WriteLine("订单当前不可以寄送");
    }
    System.Console.ReadKey();
    }
    }
    }

    QQ截图20140513165317
  • 相关阅读:
    合理的嵌入式开发学习路线
    Nginx
    RARP
    强弱电共地
    ACDC
    各电脑进Bios方法
    Java中Integer.parseInt
    全排列
    Java实现LRU缓存方案?
    缓存有关的几个问题
  • 原文地址:https://www.cnblogs.com/xiaoyaojian/p/3725983.html
Copyright © 2011-2022 走看看