1. 程式人生 > >C# Aspect-Oriented Programming(AOP) 利用多種模式實現動態代理

C# Aspect-Oriented Programming(AOP) 利用多種模式實現動態代理

style erp all 可操作性 mar targe spa min 異常

什麽是AOP(Aspect-Oriented Programming)?

AOP允許開發者動態地修改靜態的OO模型,構造出一個能夠不斷增長以滿足新增需求的系統,就象現實世界中的對象會在其生命周期中不斷改變自身,應用程序也可以在發展中擁有新的功能。

AOP利用一種稱為“橫切”的技術,剖解開封裝的對象內部,並將那些影響了多個類的行為封裝到一個可重用模塊,並將其名為“Aspect”,即方面。所謂“方面”,簡單地說,就是將那些與業務無關,

卻為業務模塊所共同調用的邏輯或責任,例如事務處理、日誌管理、權限控制等,封裝起來,便於減少系統的重復代碼,降低模塊間的耦合度,並有利於未來的可操作性和可維護性。

AOP技術本質

AOP(Aspect-Oriented Programming,面向方面編程),可以說是OOP(Object-Oriented Programing,面向對象編程)的補充和完善。OOP引入封裝、繼承和多態性等概念來建立一種對象層次結構,

用以模擬公共行為的一個集合。當我們需要為分散的對象引入公共行為的時候,OOP則顯得無能為力。也就是說,OOP允許你定義從上到下的關系,但並不適合定義從左到右的關系。例如日誌功能。

日誌代碼往往水平地散布在所有對象層次中,而與它所散布到的對象的核心功能毫無關系。對於其他類型的代碼,如安全性、異常處理和透明的持續性也是如此。這種散布在各處的無關的代碼被稱為

橫切(cross-cutting)代碼,在OOP設計中,它導致了大量代碼的重復,而不利於各個模塊的重用。

而AOP技術則恰恰相反,它利用一種稱為“橫切”的技術,剖解開封裝的對象內部,並將那些影響了多個類的公共行為封裝到一個可重用模塊,並將其名為“Aspect”,即方面。所謂“方面”,簡單地說,

就是將那些與業務無關,卻為業務模塊所共同調用的邏輯或責任封裝起來,便於減少系統的重復代碼,降低模塊間的耦合度,並有利於未來的可操作性和可維護性。AOP代表的是一個橫向的關系,

如果說“對象”是一個空心的圓柱體,其中封裝的是對象的屬性和行為;那麽面向方面編程的方法,就仿佛一把利刃,將這些空心圓柱體剖開,以獲得其內部的消息。而剖開的切面,也就是所謂的“方面”了。

然後它又以巧奪天功的妙手將這些剖開的切面復原,不留痕跡。

使用“橫切”技術,AOP把軟件系統分為兩個部分:核心關註點和橫切關註點。業務處理的主要流程是核心關註點,與之關系不大的部分是橫切關註點。橫切關註點的一個特點是,他們經常發生在核心關註點的多處,

而各處都基本相似。比如權限認證、日誌、事務處理。Aop 的作用在於分離系統中的各種關註點,將核心關註點和橫切關註點分離開來。正如Avanade公司的高級方案構架師Adam Magee所說,

AOP的核心思想就是“將應用程序中的商業邏輯同對其提供支持的通用服務進行分離。”

實現AOP的技術,主要分為兩大類:一是采用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行為的執行;二是采用靜態織入的方式,引入特定的語法創建“方面”,從而使得編譯器可以在編譯期間織入有

關“方面”的代碼。然而殊途同歸,實現AOP的技術特性卻是相同的,分別為:

1、join point(連接點):是程序執行中的一個精確執行點,例如類中的一個方法。它是一個抽象的概念,在實現AOP時,並不需要去定義一個join point。

2、point cut(切入點):本質上是一個捕獲連接點的結構。在AOP中,可以定義一個point cut,來捕獲相關方法的調用。

3、advice(通知):是point cut的執行代碼,是執行“方面”的具體邏輯。

4、aspect(方面):point cut和advice結合起來就是aspect,它類似於OOP中定義的一個類,但它代表的更多是對象間橫向的關系。

5、introduce(引入):為對象引入附加的方法或屬性,從而達到修改對象結構的目的。有的AOP工具又將其稱為mixin。

上述的技術特性組成了基本的AOP技術,大多數AOP工具均實現了這些技術。它們也可以是研究AOP技術的基本術語。

1.C# 手動實現實現靜態代理 <AOP在方法前後增加自定義的方法>

假設一個場景, 當用戶在系統登錄, 現在需要在登錄前分別做一個版本校驗, 和用戶登錄緩存處理... <利用裝飾者模式實現靜態代理實現登錄前後增加自定義方法>

/// <summary>
    /// 裝飾器模式實現靜態代理
    /// AOP在方法前後增加自定義的方法
    /// </summary>
    public class Decorator
    {
        public static void Show()
        {
            User user = new User() { Name = "Eleven", Password = "123123123123" };
            IUserProcessor processor = new UserProcessor();
            processor = new UserProcessorDecorator(processor);
            processor.RegUser(user);
        }

        public interface IUserProcessor
        {
            void RegUser(User user);
        }
        public class UserProcessor : IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine("用戶登錄, Name:{0},PassWord:{1}", user.Name, user.Password);
            }
        }

        /// <summary>
        /// 裝飾器的模式去提供一個AOP功能
        /// </summary>
        public class UserProcessorDecorator : IUserProcessor
        {
            private IUserProcessor UserProcessor { get; set; }
            public UserProcessorDecorator(IUserProcessor userprocessor)
            {
                UserProcessor = userprocessor;
            }

            public void RegUser(User user)
            {
                PreProceed(user);
                this.UserProcessor.RegUser(user);
                PostProceed(user);
            }

            public void PreProceed(User user)
            {
                Console.WriteLine("檢查軟件版本信息...");
            }

            public void PostProceed(User user)
            {
                Console.WriteLine("保存本地緩存...");
            }
        }

    }

如果沒有使用AOP, 上面的需求我們要怎麽去實現, 唯一的方法就是在執行方法的前後分別新增版本信息檢查, 和本地緩存處理。

public static void Show()
        {
            User user = new User() { Name = "Eleven", Password = "123123123123" };
            IUserProcessor processor = new UserProcessor();
            Console.WriteLine("檢查軟件版本信息...");
            processor.RegUser(user);
            Console.WriteLine("保存本地登錄緩存...");
            
            }

2.使用Castle\DynamicProxy 實現動態代理

using Castle.DynamicProxy;//Castle.Core    

///
<summary> /// 使用Castle\DynamicProxy 實現動態代理 /// </summary> public class CastleProxy { public static void Show() { User user = new User() { Name = "Eleven", Password = "123123123123" }; ProxyGenerator generator = new ProxyGenerator(); MyInterceptor interceptor = new MyInterceptor(); UserProcessor userprocessor = generator.CreateClassProxy<UserProcessor>(interceptor); userprocessor.RegUser(user); } 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 interface IUserProcessor { void RegUser(User user); } public class UserProcessor : IUserProcessor { public virtual void RegUser(User user) { Console.WriteLine("用戶登錄。Name:{0},PassWord:{1}", user.Name, user.Password); } } }

3. 使用.Net Remoting/RealProxy 實現動態代理

/// <summary>
    /// 使用.Net Remoting/RealProxy 實現動態代理
    /// </summary>
    public class Proxy
    {
        public static void Show()
        {
            User user = new User() { Name = "Eleven", Password = "123123123123" };
            UserProcessor userprocessor = TransparentProxy.Create<UserProcessor>();
            userprocessor.RegUser(user);
        }

        public class MyRealProxy<T> : RealProxy
        {
            private T tTarget;
            public MyRealProxy(T target)
                : base(typeof(T))
            {
                this.tTarget = target;
            }

            public override IMessage Invoke(IMessage msg)
            {
                PreProceede(msg);
                IMethodCallMessage callMessage = (IMethodCallMessage)msg;
                object returnValue = callMessage.MethodBase.Invoke(this.tTarget, callMessage.Args);
                PostProceede(msg);
                return new ReturnMessage(returnValue, new object[0], 0, null, callMessage);
            }
            public void PreProceede(IMessage msg)
            {
                Console.WriteLine("檢查軟件版本信息");
            }
            public void PostProceede(IMessage msg)
            {
                Console.WriteLine("保存本地登錄緩存");
            }
        }

        //TransparentProxy
        public static class TransparentProxy
        {
            public static T Create<T>()
            {
                T instance = Activator.CreateInstance<T>();
                MyRealProxy<T> realProxy = new MyRealProxy<T>(instance);
                T transparentProxy = (T)realProxy.GetTransparentProxy();
                return transparentProxy;
            }
        }

        public interface IUserProcessor
        {
            void RegUser(User user);
        }

        public class UserProcessor : MarshalByRefObject, IUserProcessor
        {
            public void RegUser(User user)
            {
                Console.WriteLine("用戶登錄。用戶名稱{0} Password{1}", user.Name, user.Password);
            }
        }

    }

C# Aspect-Oriented Programming(AOP) 利用多種模式實現動態代理