1. 程式人生 > >20181122_C#中AOP初探_裝飾器模式的AOP_Remoting實現AOP_Castle實現AOP

20181122_C#中AOP初探_裝飾器模式的AOP_Remoting實現AOP_Castle實現AOP

一.   什麼是AOP:

a)         AOP是面向切面程式設計; 就像oop一樣, 它也是一種程式設計思想;

            i.    Oop思想→一切皆物件, 物件互動組成功能, 功能疊加組成模組, 模組疊加組成系統; 如果把一個個的類比喻成一個個磚頭, 那麼系統就是一個房子; 房子是由一塊塊磚頭構成, 所以面向物件非常適合做大型系統; 但是面向物件的在應對系統擴充套件的時候, 就顯得力不從心; 如果磚塊需要發生變化, 則就會牽扯到很多地方; 因為面向物件是靜態的, 內部就是強耦合的關係; 雖然設計模式可以解決這些問題中的某些部分, 比如可以創建出可擴充套件, 可重用的架構, 但是設計模式操作的最小單元也是類(磚頭), 無法解決類的內部的變化

           ii.   AOP→面向切面程式設計, 是對OOP的補充; 主要功能就是為了解決類的內部變化, 在不破壞類封裝的同時, 水平擴充套件類的功能; 降低模組間的耦合度; 注意AOP不是實現業務行為的: 比如一個People類, 本身具有跑步, 吃飯, 睡覺這三個方法, 但是如果你想通過AOP為其增加一個 游泳 的方法, 那麼AOP就不適用了; 因為這種屬於業務層面, 在封裝類的時候, 就應該存在的行為; AOP主要是用來做一些通用的功能, 比如 許可權校驗/日誌記錄/傳送訊息/快取處理/效能監控 等等一些通用的非業務邏輯

的功能;

          iii.    總結:

    1. 所以說AOP 只是對OOP思想的一種補充, 解決類的內部通用功能的變化
    2. 所有的業務功能還是由OOP來實現, 比如People類需要增加 游泳 方法, 還是得有OOP來完成
    3. 有了AOP之後, OOP的實現也變得簡單了, 因為OOP的程式碼, 只用關注業務邏輯; 無需再操心各種通用的功能了

二. 利用裝飾器模式實現簡答的AOP, 沒有通用性:

a)         實現程式碼:

/// <summary>
        /// 1. 這個介面定義一個註冊使用者的行為
        /// </summary>
        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        /// <summary>
        /// 2. 普通的實現
        /// </summary>
        public class UserProcessor : IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine("使用者已註冊。Name:{0},PassWord:{1}", user.Name, user.Password);
            }
        }

        /// <summary>
        /// 3. 利用裝飾器模式的實現, 這個就類似於簡單的AOP功能,
        /// 裝飾器即實現了IuserProcessor的介面
        /// 但在實現的同時, 還組合進一個IuserProcessor物件; 
        /// 這就是一個標準的裝飾器模式
        /// </summary>
        public class UserProcessorDecorator : IUserProcessor
        {
            //組合一個IUserProcessor物件
            private IUserProcessor _UserProcessor { get; set; }
            public UserProcessorDecorator(IUserProcessor userprocessor)
            {
                this._UserProcessor = userprocessor;
            }
            //實現介面
            public void RegUser(User user)
            {
                BeforeProceed(user);

                this._UserProcessor.RegUser(user);

                AfterProceed(user);
            }

            /// <summary>
            /// 定義在業務邏輯執行之前要執行的動作
            /// </summary>
            /// <param name="user"></param>
            private void BeforeProceed(User user)
            {
                Console.WriteLine("方法執行前");
            }
            /// <summary>
            /// 定義在業務邏輯執行之後要執行的動作
            /// </summary>
            /// <param name="user"></param>
            private void AfterProceed(User user)
            {
                Console.WriteLine("方法執行後");
            }
        }

b) 呼叫

public static void Show()
{
    User user = new User()
    {
        Name = "孫悟空",
        Password = "123456"
    };

    //5. 裝飾器模式使用的方法
    IUserProcessor processor = new UserProcessor();
    processor.RegUser(user); //普通實現


    Console.WriteLine("***************");



    user = new User()
    {
        Name = "八戒AOP",
        Password = "567890"
    };
    processor = new UserProcessorDecorator(processor);
    processor.RegUser(user);//使用裝飾器模式實現的AOP, 看起來只為此類的此方法單獨實現的, 有很大侷限性
}

c)  執行結果截圖:

 

 三.  使用.net Remoting實現動態代理(AOP), 不太推薦, .net Remoting對父類的限制實在是太大了

a)         建立一個介面, 這裡和裝飾器模式沒有什麼區別

 /// <summary>
        /// 1. 使用.net Remoting 來實現動態代理, 這裡的業務還是和裝飾器與代理模式的業務一樣
        /// </summary>
        public interface IUserProcessor
        {
            void RegUser(User user);
        }

b)  實現介面, 並繼承MarshalByRefObject

 

 /// <summary>
        /// 必須繼承自MarshalByRefObject父類,否則無法生成; 
        /// 這個繼承就感覺比較噁心了;因為C#中都是單繼承的
        /// 
        /// 2. 定義一個UserProcessor來實現IUserProcessor, 必須繼承一個MarshalByRefObject; 繼承此類是.net Remoting的固定寫法類; 如果想實現動態代理就必須繼承這個類(MarshalByRefObject)
        /// </summary>
        public class UserProcessor : MarshalByRefObject, IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine("使用者已註冊。使用者名稱稱{0} Password{1}", user.Name, user.Password);
            }
        }

c)  使用Remoting進行物件生成的動態代理的固定寫法

/// <summary>
        /// MyRealProxy<T> 就是真實代理, 這個類裡面的東西, 屬於固定寫法, 是.net Remoting封裝好的
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public class MyRealProxy<T> : RealProxy
        {
            private T tTarget;
            public MyRealProxy(T target): base(typeof(T))
            {
                this.tTarget = target;
            }

            /// <summary>
            /// .net Remoting的核心方法
            /// </summary>
            /// <param name="msg"></param>
            /// <returns></returns>
            public override IMessage Invoke(IMessage msg)
            {
                BeforeProceede(msg); //在執行方法之前做一些其它自定義的動作

                //這裡執行真實的方法體, 在這個方法體之前(之後)都可以加一點自己的動作
                IMethodCallMessage callMessage = (IMethodCallMessage)msg;
                object returnValue = callMessage.MethodBase.Invoke(this.tTarget, callMessage.Args);

                AfterProceede(msg);//在執行方法之後執行一些其它動作

                return new ReturnMessage(returnValue, new object[0], 0, null, callMessage);
            }
            #region 可以擴充套件的邏輯
            public void BeforeProceede(IMessage msg)
            {
                Console.WriteLine("方法執行前可以加入的邏輯");
            }
            public void AfterProceede(IMessage msg)
            {
                Console.WriteLine("方法執行後可以加入的邏輯");
            }
            #endregion
        }
/// <summary>
        /// 透明代理; 固定的寫法, 表示如何使用.net Remoting來生成物件
        /// </summary>
        public static class TransparentProxy
        {
            public static T Create<T>()
            {
                //使用反射動態建立物件
                T instance = Activator.CreateInstance<T>();
                //將物件包裝一層, 交給MyRealProxy
                MyRealProxy<T> realProxy = new MyRealProxy<T>(instance);
                //GetTransparentProxy→父類的方法
                T transparentProxy = (T)realProxy.GetTransparentProxy();
                return transparentProxy;
            }
        }

d) 呼叫方法:

 

public static void Show()
{
    User user = new User()
    {
        Name = "孫悟空",
        Password = "123456"
    };

    UserProcessor processor = new UserProcessor();
    processor.RegUser(user);
    Console.WriteLine("*********************");

    user = new User()
    {
        Name = "八戒AOP",
        Password = "567890"
    };
    //利用TransparentProxy來建立物件
    UserProcessor userProcessor = TransparentProxy.Create<UserProcessor>();
    //呼叫RegUser時, 會進入到Invoke方法中, 至於為什麼會進入到Invoke中, 是由.net Remoting的底層來實現的
    userProcessor.RegUser(user);
}

e)         執行結果:

四.   使用Castle實現動態代理

   對於Castle來說, 實現介面時, 方法必須是一個虛方法; 主要程式碼如下:

/// <summary>
    /// 使用Castle\DynamicProxy 實現動態代理
    /// 方法必須是虛方法
    /// </summary>
    public class CastleProxyAOP
    { 
        /// <summary>
        /// 1. 業務和動態代理/裝飾器模式/.net Remoting(RealProxy)都是一樣, 定義介面物件
        /// </summary>
        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        /// <summary>
        /// 2. 業務子類實現IUserProcessor介面
        /// </summary>
        public class UserProcessor : IUserProcessor
        {
            /// <summary>
            /// 必須帶上virtual 否則無效
            /// </summary>
            /// <param name="user"></param>
            public virtual void RegUser(User user)
            {
                Console.WriteLine($"使用者已註冊。Name:{user.Name},PassWord:{user.Password}");
            }
        }

        /// <summary>
        /// 3. 這裡是個重點, Intercept()方法是個重點
        /// </summary>
        public class MyInterceptor : IInterceptor
        {
            public void Intercept(IInvocation invocation)
            {
                //在方法呼叫之前執行的動作
                PreProceed(invocation);
                invocation.Proceed(); //這裡是真實的方法呼叫
                //在方法呼叫之後執行的動作
                PostProceed(invocation);
            }
            public void PreProceed(IInvocation invocation)
            {
                Console.WriteLine("方法執行前");
            }

            public void PostProceed(IInvocation invocation)
            {
                Console.WriteLine("方法執行後");
            }
        }

			public static void Show()
        {
            User user = new User()
            {
                Name = "孫悟空",
                Password = "456789"
            };

            //4. 呼叫
            ProxyGenerator generator = new ProxyGenerator();
            MyInterceptor interceptor = new MyInterceptor();

            //5. 建立物件; (這個也是動態實現的AOP); 固定寫法
			  // 基於裡式替換原則,右邊是父類, 那麼在呼叫的時候, 根本就不會去管左邊是個什麼, 直接會呼叫父類的RegUser方法, 如果要呼叫子類的RegUser方法, 則必須標註virtual
            UserProcessor userprocessor = generator.CreateClassProxy<UserProcessor>(interceptor);
            userprocessor.RegUser(user);
        } 

    }