本文是講使用微軟企業庫來實現AOP和IoC/DI的,大家先裝下微軟企業庫5.0,地址:http://www.microsoft.com/en-us/download/details.aspx?id=15104
AOP的實現,使用PIAB(Policy Injection Application Block)
比如想給這個TestManager類的Method2方法檢查權限,有權限時才允許執行Method2方法體,最初的代碼如下:
public class TestManager { public void Method2(int x) { Console.WriteLine("output222:{0}", x); } }
下面是改造后的代碼:
static class Identity//這個類純屬是為了權限而寫的一個很簡單的mock用戶是否login的類 { public static int UserID { get; set; }//如果UserID>0代表合法用戶 } public class TestManager : MarshalByRefObject //這個MarshalByRefObject必須加上 { [PermissionCheckHandlerAttribute] //在目標方法上加上自定義的Attribute(可以多個,就看需求了),這個Attribute必須繼承於HandlerAttribute public void Method2(int x) { Console.WriteLine("output222:{0}", x); } } public class PermissionCheckHandler : ICallHandler //這個類是最終AOP要掛載上去的,橫切邏輯就在這個類中,這個類必須實現ICallHandler { public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { if(Identity.UserID>0) return getNext()(input, getNext); //這句就代表繼續執行后續操作,這個后續操作也許是后續的AOP橫切點,也許是真正的業務方法調用(隨需求) return input.CreateExceptionMethodReturn(new Exception("Permission Denied")); //當報錯需要拋異常時,需要用這個方法來生成,不能直接throw new exception } public int Order { get; set; } //當多個AOP橫切點存在時,這個Order屬性代表優先順序,數字越低,優先級越高 } [AttributeUsage(AttributeTargets.Method)] //這句可以不寫 public class PermissionCheckHandlerAttribute : HandlerAttribute //這個class是最終被貼到業務方法上的Attribute,這個Attribute用來把{業務函數/方法 和 橫切點} 綁定起來 { public override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container) { return new PermissionCheckHandler(); //返回橫切點class } }
最終調用的代碼:
TestManager mgrProxy = PolicyInjection.Create<TestManager>(); //這個就是PIAB入口,能夠根據目標class生成代理 Identity.UserID = 0; try { mgrProxy.Method2(1); } catch(Exception ex) { Console.WriteLine("1111111111111-->"+ex.Message); } Identity.UserID = 1; try { mgrProxy.Method2(2); } catch (Exception ex) { Console.WriteLine("2222222222222-->" + ex.Message); } Console.ReadKey();
運行如下:
下面來看看使用Unity時,IoC/DI的實現
初始代碼如下(一個interface, 分別有2個具體的實現,很簡單):
public interface IManager { void Method1(int x); } public class Manager1 : IManager { public void Method1(int x) { Console.WriteLine("Manager1-->"+x); } } public class Manager2 : IManager { public void Method1(int x) { Console.WriteLine("Manager2-->" + x); } }
程序中,為了達到隔離的目的,只依賴接口,如下代碼:
IUnityContainer container = new UnityContainer(); container.RegisterType<IManager, Manager1>(); container.RegisterType<IManager, Manager2>("mgr2"); //當一個Interface擁有多個具體實現的時候,就需要用這種別名的形式標識了 IManager mgr = container.Resolve<IManager>(); //得到默認實例 mgr.Method1(1); mgr = container.Resolve<IManager>("mgr2"); //得到命名實例 mgr.Method1(2); Console.ReadKey();
運行如下:
下面我們來看看更加智能的IoC/DI
上面說的那個IManager的具體實現類,都是默認構造器,我們增加一個具體實現,如下:
public class Manager3 : IManager { private ILog log; public Manager3(ILog log) //多了個依賴ILog,並且這個Manager3沒有默認構造器 { this.log = log; } public void Method1(int x) { Console.WriteLine("Manager2-->" + x); log.Write(x.ToString()); } }
咋辦呢?難道要Resolve ILog后,再手工放入Manager3?不用,哈哈,如下:
container.RegisterType<ILog, Log1>(); //頁注冊一個Log進去 container.RegisterType<IManager, Manager3>("mgr3"); //注冊一個明明實例 mgr = container.Resolve<IManager>("mgr3"); //直接拉出一個mgr就好,一點都不麻煩,哈哈 mgr.Method1(3); Console.ReadKey();
運行如下:
AOP能結構化很多橫切點(日志、事務、權限等)
IoC/DI能簡化很多代碼...