• 订单的几种实现方式(用不同的模式实现:装饰器模式、代理模式、命令模式、状态模式、模版模式)


    谈谈下订单的几种实现方式(用不同的模式实现:装饰器模式、代理模式、命令模式、状态模式、模版模式)

    本文讲PlaceOrder函数的实现(重点在业务逻辑层),让我们来分别用不同的设计模式来实现吧:装饰器模式、代理模式、命令模式、状态模式、模版模式。

    假设我们实现需求如下:
                   在PlaceOrder函数中需要做如下工作
                   1. 检查权限,未登录的不能递交订单
                   2. 计算税
                   3. 记录日志
    好了,让我们分别来实现吧....当然,是用不同的设计模式分别实现。

    装饰器模式实现

    请看PlaceOrder函数方法体:

    复制代码
    public bool PlaceOrder(OrderInfo order)
            {
                try
                {
                    OrderService srv = new OrderService();                                 //核心业务类
                    TaxDecorator4OrderService tax = new TaxDecorator4OrderService(srv);    //第一次装饰
                    LogDecorator4OrderService log = new LogDecorator4OrderService(tax);    //第二次装饰
                    PermissionDecorator4OrderService permission = new PermissionDecorator4OrderService(log);//第三次装饰
    
                    return permission.NewOrder(order); //这里调用的是最后一个装饰器的方法(会链式反应,调用全部的关联函数)
                }
                catch(Exception ex)//由于PermissionDecorator4OrderService中会抛出exception,因此用了try, catch
                {
                    Console.WriteLine("exception: "+ex.Message);
                    return false;
                }
            }
    复制代码

     实现方法

                1. 写一个公共的接口,让“核心业务类”、“装饰类”都实现这个接口
                2. “装饰类”的构造器需要能注入这个公共接口
                3. 然后像上面那样拼装饰链条
    装饰器代码如下(核心代码):

    复制代码
    public class PermissionDecorator4OrderService:IOrderServiceComponent             //上面所说的公共接口
        {
            IOrderServiceComponent component;
            public PermissionDecorator4OrderService(IOrderServiceComponent component)  //要提供注入的地方,此处是构造函数注入方式,你也可以根据情况使用其他注入方式
            {
                this.component = component;
            }
            public bool NewOrder(OrderInfo order)
            {
                if (Identity.UserID <= 0)
                    throw new Exception("Authorization exception");
                return this.component.NewOrder(order);
            }
        }
    复制代码

     代码在本页最下方有下载。

    代理模式实现

    请看PlaceOrder函数方法体:

    复制代码
    public bool PlaceOrder(OrderInfo order)
            {
                try
                {
                    OrderService srv = new OrderService();                         //核心业务类(这个类就是要被控制访问的类)
                    OrderServiceAgency srvAgency = new OrderServiceAgency();       //代理类,外界的调用是通过它的,由它来转发核心业务类的调用,意图在于控制访问
                    srvAgency.SetServiceComponent(srv);                            //此处为注入(方法注入方式),当然,你也可以使用构造器注入
    
                    return srvAgency.NewOrder(order);                              //看,此处调用的是代理的NewOrder
                }
                catch(Exception ex)
                {
                    Console.WriteLine("exception: "+ex.Message);
                    return false;
                }
            }
    复制代码

      “核心业务类”、“代理类”,这2个类的外观是相同的,最简单的方式实现这个模式是

                        1. 为这2种类定义一个接口,这2种类都去实现
                        2. “代理类”除了要实现这个接口之外,还要持有这个接口的一个instance(这样才能转发调用)
                        3. “代理类”需要提供注入方式:构造函数、方法、属性注入方式
    “代理类”代码如下(核心):

    复制代码
    public class OrderServiceAgency : IOrderServiceComponent                     //实现同一个接口(外观一致)
        {
            private IOrderServiceComponent component;                            //要持有一个instance
            public void SetServiceComponent(IOrderServiceComponent component)    //注入这个instance
            {
                this.component = component;
            }
            public bool NewOrder(OrderInfo order)                                 //“代理类”的接口方法中,可以自定义一些逻辑
            {
                if (Identity.UserID <= 0)
                    throw new Exception("Authorization exception");
    
                order.Total += order.Total * (decimal)0.02;//模拟税收
    
                Console.WriteLine("loging...");
    
                return this.component.NewOrder(order);                            //转发请求到“业务类”
            }
        }
    复制代码

     代码在本页最下方有下载。

    命令模式

     请看PlaceOrder函数方法体:

    复制代码
    public bool PlaceOrder(OrderInfo order)
            {
                try
                {
                    NewOrderCommandResult result=new NewOrderCommandResult();            //由于命令模式不像直接call、返回结果方式,因此写了这个callback类,专门用来放执行结果
    
                    CheckPermissionCommand permissionCommand = new CheckPermissionCommand(new RealExecuters.PermissionService());  //检查权限命令
                    CalculateTaxCommand calculateTaxCommand = new CalculateTaxCommand(new RealExecuters.TaxCalculator(), order);   //计算税命令
                    LogCommand logCommand = new LogCommand(new RealExecuters.LogService());                                        //记录日志命令
                    NewOrderCommand newOrderCommand=new NewOrderCommand(new RealExecuters.OrderService(), order, result);          //调用"核心业务类"命令
    
                    List<IPlaceOrderCommand> list = new List<IPlaceOrderCommand>();        //把这些命令都打包到一个list中
                    list.Add(permissionCommand);
                    list.Add(calculateTaxCommand);
                    list.Add(logCommand);
                    list.Add(newOrderCommand);
    
                    list.ForEach(t=>t.Execute());                                           //遍历执行
    
                    return result.IsSuccess;                                                //callback的执行结果
                    
                }
                catch(Exception ex)
                {
                    Console.WriteLine("exception: "+ex.Message);
                    return false;
                }
            }
    复制代码

     原本的调用方式是直接call,然后目标对象返回结果,命令模式是在这步骤中间截取了一道,它通过增加一个command类来中转对目标方法的调用,此时,只要保存这些command类就能打包命令的执行了。

    核心代码如下:

    复制代码
    interface IPlaceOrderCommand              //命令的抽象接口
        {
            void Execute();                   //就那么一个方法,Execute(), 而且是void和没有参数的
        }
    class LogCommand : IPlaceOrderCommand
        {
            private LogService logService;
            public LogCommand(LogService logService)  //不同的Command需要注入相应的真正实现这个命令的类
            {
                this.logService = logService;
            }
    
            public void Execute()
            {
                this.logService.Log("loging...");      //只是中转调用
            }
        }
    class PermissionCheckCommand: IPlaceOrderCommand

      class Log2Command:IPlaceOrderCommand

    复制代码

     当这些XXXXXXXCommand被instance之后,就可以保存到Queue或者List,又或者序列化。。。。统一Execute(),而且此时执行的话,外观已经一致了,并且没有入参,很方便。

    至于这个模式的callback result怎么写,大家就看看demo代码吧,这里不说了。

    代码在本页最下方有下载。

    状态模式 

    请看PlaceOrder函数方法体:

    复制代码
    public bool PlaceOrder(OrderInfo order)
            {
                try
                {
                    bool isValidaUser = Identity.UserID > 0;
                    IOrderServiceComponent component=null;
                    if (isValidaUser)                                            //根据条件状态,去获取不同的对象,执行不一样的业务逻辑
                        component = new AuthorizaedNewOrderService();
                    else
                        component = new UnAuthorizaedNewOrderService();
                    return component.NewOrder(order);
                }
                catch(Exception ex)
                {
                    Console.WriteLine("exception: "+ex.Message);
                    return false;
                }
            }
    复制代码

     主要的原理是:把代码中大块的if/else中的代码extract到其他class中,实现要点:

                           1. 有几个分支,就写几个类,然后把if/else中的代码重构过去
                           2. 这些新增的类,需要实现同一个接口
    核心代码如下:

    复制代码
    public interface IOrderServiceComponent
        {
            bool NewOrder(OrderInfo order);
        }
    class UnAuthorizaedNewOrderService : IOrderServiceComponent
        {
            public bool NewOrder(OrderInfo order)
            {
                throw new Exception("Authorization exception");
            }
        }
    class AuthorizaedNewOrderService : IOrderServiceComponent
        {
            public bool NewOrder(OrderInfo order)
            {
                order.Total += order.Total * (decimal)0.02;//模拟税收
                //validate entity
                //insert database
                Console.WriteLine("inserting database");
                Console.WriteLine("loging...");
                return true;
            }
        }
    复制代码

     代码在本页最下方有下载。

    模版模式 

    请看PlaceOrder函数方法体: 

    复制代码
    public bool PlaceOrder(OrderInfo order)
            {
                try
                {
                    BaseOrderService srv = new AaronOrderService();  //BaseOrderService是定义的模版抽象类,里面定义了NewOrder函数的主要步骤逻辑
                    return srv.NewOrder(order);                      //AaronOrderService只是重写/实现BaseOrderService的某些方法函数,达到部分自定义,全局固定的状态
                }
                catch(Exception ex)
                {
                    Console.WriteLine("exception: "+ex.Message);
                    return false;
                }
            }
    复制代码

    这个模式在平台设计上也很有用,因为能够做到全局固定、局部变化,简而言之:该不变的就不变、该变的就要变,也有称为热点的。

    核心代码如下:

    复制代码
    public abstract class BaseOrderService
        {
            public bool NewOrder(OrderInfo order)             //这个就是骨架了,逻辑步骤是固定住的
            {
                PermissionCheck();
                TaxCalculate(order);
                bool success=CreateNewOrder(order);
                Log();
                return success;
            }
    
            private void Log()
            {
                Console.WriteLine("loging...");
            }
    
            protected abstract bool CreateNewOrder(OrderInfo order);    //这个函数没有实现,是需要去实现的
    
            protected virtual void TaxCalculate(OrderInfo order)        //这个函数实现了,但是定义成了virtual, 允许子类override
            {
                order.Total += order.Total * (decimal)0.02;
            }
    
            private void PermissionCheck()
            {
                if (Identity.UserID <= 0)
                    throw new Exception("Authorization exception");
            }
        }
    复制代码

    下载demo 代码

    自省推动进步,视野决定未来。
    心怀远大理想。
    为了家庭幸福而努力。
     
    分类: 设计模式
  • 相关阅读:
    使用变焦摄影镜头的10条经验
    Savage 2:灵魂拷问者Linux即时战略游戏
    在FlashCom中检测摄像头和麦克风的方法
    Asp.net 在线转Flv
    linux的启动加密
    一个命令轻轻松松重新初始化Ubuntu软件包
    Firefox扩展开发学习杂记
    使用 XUL 实现浏览器扩展,第 1 部分: 使用用户界面特性创建一个 Firefox 浏览
    ffmpeg参数解释中文详细
    用mencoder解决ffmpeg转换wmv/asf to flv花屏的问题,并支持rm/rmvb
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3017938.html
Copyright © 2020-2023  润新知