Spring.NET教程(十)——面向切面编程(基础篇)
下面我举个例子来说明这一切:
场景:业务类CompanyManager在调用Save方法的时候需要调用SecurityManager类判断权限是否足够(图1)。
图1
准备条件:
public class CompanyDao
{
public void Save()
{
Console.WriteLine("保存数据");
}
}
public interface ICompanyManager
{
string UserName { get; set; }
void Save();
}
public interface ISecurityManager
{
bool IsPass(string userName);
}
SecurityManager
public class SecurityManager : ISecurityManager
{
/**//// <summary>
/// 判断权限
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public bool IsPass(string userName)
{
return userName == "admin";
}
}
第一种实现方式,我们通常会这样做:直接在CompanyManager类中调用ISecurityManager接口的IsPass方法判断权限。
SimpleCompanyManager
public class SimpleCompanyManager : ICompanyManager
{
可通过外部注入的属性#region 可通过外部注入的属性
public string UserName { get; set; }
public CompanyDao Dao { get; set; }
#endregion
public void Save()
{
//判断权限
ISecurityManager security = new SecurityManager();
if (security.IsPass(UserName))
{
//执行业务方法
//.
//调用DAO层方法
Dao.Save();
}
else
{
//执行其它业务方法
Console.WriteLine("您没有该权限");
}
}
}
这样CompanyManager类与ISecurityManager或SecurityManager会发生业务性耦合。聪明的朋友会发现在GOF(设计模式)中有一种模式(代理模式)可以解除这种耦合。
第二种实现方式,代理模式(Proxy Pattern):什么是代理模式?是给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系统的其他角色代为创建并传入(图2)。
图2
CompanyManager
public class CompanyManager : ICompanyManager
{
可通过外部注入的属性#region 可通过外部注入的属性
public string UserName { get; set; }
public CompanyDao Dao { get; set; }
#endregion
public void Save()
{
//执行业务方法
//.
//调用DAO层方法
Dao.Save();
}
}
CompanyProxyManager
public class CompanyProxyManager : ICompanyManager
{
public string UserName { get; set; }
private ICompanyManager target = new CompanyManager();
public void Save()
{
//判断权限
ISecurityManager security = new SecurityManager();
if (security.IsPass(UserName))
{
//调用目标对象Save方法
target.Save();
}
else
{
Console.WriteLine("您没有该权限");
}
}
}
这样,CompanyManager类就不必与判断权限的类SecurityManager耦合,但是这种方式实现起来比较麻烦。
第三种实现方式,Spring.NET提供的AOP:AopAlliance.Intercept.IMethodInterceptor接口和ProxyFactory类的组合。
AroundAdvice
public class AroundAdvice : IMethodInterceptor
{
//权限系统类(可外部注入)
private ISecurityManager manager = new Service.SecurityManager();
public object Invoke(IMethodInvocation invocation)
{
//拦截Save方法
if (invocation.Method.Name == "Save")
{
ICompanyManager target = (ICompanyManager)invocation.Target;
return manager.IsPass(target.UserName) ? invocation.Proceed() : null;
}
else
{
return invocation.Proceed();
}
}
}
Program
class Program
{
static void Main(string[] args)
{
ICompanyManager target = new CompanyManager() { Dao = new CompanyDao(), UserName = "admin" };
ProxyFactory factory = new ProxyFactory(target);
factory.AddAdvice(new AroundAdvice());
ICompanyManager manager = (ICompanyManager)factory.GetProxy();
manager.Save();
Console.ReadLine();
}
}
输出:保存数据
Spring.NET利用System.Reflection.Emit命名空间下的类在运行时动态创建IL代码来生成AOP代理。这使得代理(的创建)非常高效,并且不受任何继承层次的限制。