談談下訂單的幾種實現方式(用不同的模式實現:裝飾器模式、代理模式、命令模式、狀態模式、模版模式)


本文講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 代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM