代理模式及AOP

在平常的生活中,我们有很多代理的场景。比如找房,找工作的各种中介机构。举个例子来说:我想买个二手房,虽然我可以自己去找房源,做验房等一系列的不动产过户流程,但是这太浪费我得时间和精力了。我只是想买一个二手房为什么还要额外做这么多事呢?于是我就通过中介公司来买房,他们来给我找房源,帮我办理过户流程,我只是负责选择自己喜欢的,然后付钱就可以了。我们会发现中介代理的东西给用户使用,实际上提供真实服务的是被代理的对象,真正卖房给我的是房东;中介在卖房这个事给我提供额外服务。在软件开发中适当的运用代理的模式可以统一的管理一批服务,对使用方只需要面对代理对象就行了,减少服务提供方和使用方的压力。

代理模式结构图
代理模式

从结构图上我们可以看到代理类实现和委托的服务类同样的接口,这样对于使用方如果面向接口编程的话,给他一个委托类和代理类是一样的,并不会影响到他的代码结构。这里代理类实现了和委托类同样的接口,但是并没有真实的业务逻辑的实现,作为代理也不关心业务逻辑的实现,为了满足接口申明的功能,代理类内部持有委托类的对象。接口方法实现里面直接到委托类对象的方法来做业务。这样代理类就有了被代理对象的业务能力。并且在执行委托对象方法前后可以加入自己的逻辑(记录日志、安全验证、捕获异常等)。下面以两个数的加法实现代理类来说明。

首先声明一个基类或接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace 多态
{

    /// <summary>
    /// 对两个数字操作的基类
    /// </summary>
    public class Operation
    {
        /// <summary>
        /// 数字1
        /// </summary>
        public double Num1
        {
            get;
            set;
        }

        /// <summary>
        /// 数字2
        /// </summary>
        public double Num2
        {
            get;
            set;
        }

        /// <summary>
        /// 得到操作结果
        /// </summary>
        /// <returns></returns>
        public virtual double GetResult()
        {
            return 0;
        }
    }
}

委托的服务类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.Logging.Simple;
using Common.Logging;

namespace 多态
{
    /// <summary>
    /// 加
    /// </summary>
    public class ADD:Operation 
    {
        /// <summary>
        /// 日志
        /// </summary>
        private ILog loger = LogManager.GetLogger(typeof(ADD));

        /// <summary>
        /// 得到结果
        /// </summary>
        /// <returns></returns>
        public override double GetResult()
        {
            //loger.Info("调用ADD方法,参数为"+Num1 +"和"+Num2);
            //loger.Info("返回值为" + (Num1 + Num2));
            return Num1 + Num2;
        }
    }
}

实现代理类(在调用前后加额外逻辑)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.Logging.Simple;
using Common.Logging;
using 多态;

namespace 代理
{
    class ADDProxy : Operation
    {
        /// <summary>
        /// 操作基类
        /// </summary>
        private Operation add;

        /// <summary>
        /// 日志
        /// </summary>
        private ILog loger = LogManager.GetLogger(typeof(ADDProxy));

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="add"></param>
        public ADDProxy(Operation add)
        {
            this.add = add;
        }

        /// <summary>
        /// 得到结果
        /// </summary>
        /// <returns></returns>
        public override double GetResult()
        {
            #region 调用前做的操作
            loger.Info("调用ADD方法,参数为" + add.Num1 + "和" + add.Num2);
            Ivaliudate(add.Num1);
            Ivaliudate(add.Num2);
            #endregion
            double ret = 0;
            try
            {
                ret = add.GetResult();
            }
            catch (Exception ex)
            {
                loger.Info("发生异常:" + ex.Message);
            }
            #region 调用后做的操作
            loger.Info("返回值为" + ret);
            #endregion
            return ret;
        }

        /// <summary>
        /// 验证方法
        /// </summary>
        /// <param name="num"></param>
        private void Ivaliudate(double num)
        {
            if (num < 0)
            {
                throw new Exception("不能小于0");
            }
        }
    }
}

使用代理类这样就有方法入口参数捕获、返回结果日志、异常日志的额外功能了

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using 多态;

namespace 代理
{
    class Program
    {
        static void Main(string[] args)
        {
            Operation add=new ADD();
            Console.WriteLine("请输入第一个加数");
            add.Num1=Convert.ToDouble(Console.ReadLine());
            Console.WriteLine("请输入第二个加数");
            add.Num2 = Convert.ToDouble(Console.ReadLine());

            //使用代理类(这里直接new委托对象了,实际运用工厂模式反射来获取对象)
            Operation  proxy = new ADDProxy(add);

            Console.WriteLine("结果为"+proxy.GetResult());
            Console.ReadLine();
        }
    }
}

实际使用中建议使用接口编程,用接口把操作抽象出来。

实际用途(AOP)
看了上面的实现觉得并没有什么用处啊,还得多此一举的把原来对象包装代理后再使用,增加代码量和绕个圈。之所以有这个想法是因为上面例子的代理类都是我们自己写代理类代码实现的。如果能够程序自动生成代理类呢?自动生成代理类后我们能实现什么?
程序自动生成代理类之后我门能有一个AOP切面的概念。平常的类、对象、方法是一个纵向的概念,从上到下、从外到内。切面是多个类、方法之间的水平方向。我们把执行委托类方法前的逻辑抽象一个“前操作”的接口,把方法后执行的逻辑抽象一个“后操作”的接口,把捕获异常的这种操作抽象一个“环绕”的接口(统称为拦截器)。

前操作和后操作接口(拦截器接口)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GreenFramAop
{
    //后置通知接口
    public interface IInterceptor
    {

        /// <summary>
        /// 方法调用前
        /// </summary>
        /// <param name="operationName">方法名</param>
        /// <param name="inputs">参数</param>
        /// <returns>状态对象,用于调用后传入</returns>
        object BeforeCall(string operationName, object[] inputs);


        /// <summary>
        /// 方法调用后
        /// </summary>
        /// <param name="operationName">方法名</param>
        /// <param name="returnValue">结果</param>
        /// <param name="correlationState">状态对象</param>
        void AfterCall(string operationName, object returnValue, object correlationState);
    }
}

拦截器实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyAop
{
    /// <summary>
    /// [功能描述: 拦截器的实现,技术探索]<br></br>
    /// [创建者:   张联珠]<br></br>
    /// [创建时间: 2013-9-5]<br></br>
    /// <说明>
    ///    
    /// </说明>
    /// <修改记录>
    ///     <修改时间></修改时间>
    ///     <修改内容>
    ///            
    ///     </修改内容>
    /// </修改记录>
    /// </summary>
    public class StandardInterceptor : IInterceptor
    {


        public object BeforeCall(string operationName, object[] inputs)
        {
            Console.WriteLine("Before call :{0}", operationName);
            return null;
        }

        public void AfterCall(string operationName, object returnValue, object correlationState)
        {
            Console.WriteLine("After call :{0} resule: {1}  State:{2}", operationName, returnValue ?? "Null", correlationState);
        }
    }
}

拦截器工厂(创建拦截器对象用)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MyAop
{
    /// <summary>
    /// [功能描述: 简单的拦截器工厂,技术探索]<br></br>
    /// [创建者:   张联珠]<br></br>
    /// [创建时间: 2013-9-5]<br></br>
    /// <说明>
    ///    
    /// </说明>
    /// <修改记录>
    ///     <修改时间></修改时间>
    ///     <修改内容>
    ///            
    ///     </修改内容>
    /// </修改记录>
    /// </summary>
    public class DefaultInterceptorFactory
    {
        public static IInterceptor Create(Type type)
        {
            return new StandardInterceptor();
        }
    }
}

利用反射发出创建动态代理类(融合拦截器和委托类)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;

namespace MyAop
{
    /// <summary>
    /// [功能描述: 默认代理创建器,技术探索]<br></br>
    /// [创建者:   张联珠]<br></br>
    /// [创建时间: 2013-9-5]<br></br>
    /// <说明>
    ///    
    /// </说明>
    /// <修改记录>
    ///     <修改时间></修改时间>
    ///     <修改内容>
    ///            
    ///     </修改内容>
    /// </修改记录>
    /// </summary>
    public static class DefaultProxyBuilder
    {
        /// <summary>
        /// void类型
        /// </summary>
        private static readonly Type VoidType = Type.GetType("System.Void");

        /// <summary>
        /// 创建代理对象
        /// </summary>
        /// <typeparam name="T">要创建代理的类型</typeparam>
        /// <returns>代理类型</returns>
        public static T CreateProxy<T>()
        {
            //获得T的类型
            Type classType = typeof(T);

            //代理类型的命名空间
            string name = classType.Namespace + ".Aop";
            //代理类型程序集的名字
            string fileName = name + ".dll";

            //定义程序集的唯一标识
            var assemblyName = new AssemblyName(name);
            //定义动态程序集
            var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,AssemblyBuilderAccess.RunAndSave);
            //定义动态模块                                                                  
            var moduleBuilder = assemblyBuilder.DefineDynamicModule(name, fileName);
            //根据所给的类型和模块构建新类型(该类型的代理)
            var aopType = BulidType(classType, moduleBuilder);
            //保存程序集
            assemblyBuilder.Save(fileName);
            //返回构建的代理类型
            return (T)Activator.CreateInstance(aopType);
        }

        /// <summary>
        /// 根据所给的类型和模块在该模块下构建该类型的代理类型
        /// </summary>
        /// <param name="classType">所要构建代理的类型</param>
        /// <param name="moduleBuilder">所在模块</param>
        /// <returns>构建的代理类型</returns>
        private static Type BulidType(Type classType, ModuleBuilder moduleBuilder)
        {
            //代理类型的名字
            string className = classType.Name + "Proxy";

            //根据所给的类型定义类型
            var typeBuilder = moduleBuilder.DefineType(className,
                                                       TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class,
                                                       classType);
            //定义字段(拦截器) inspector
            var inspectorFieldBuilder = typeBuilder.DefineField("inspector", typeof(IInterceptor),
                                                                FieldAttributes.Private | FieldAttributes.InitOnly);
            //构造代理的构造函数
            BuildCtor(classType, inspectorFieldBuilder, typeBuilder);

            //构造代理的方法
            BuildMethod(classType, inspectorFieldBuilder, typeBuilder);

            //得到构造之后的代理类型
            Type aopType = typeBuilder.CreateType();
            //返回生成的代理类型
            return aopType;
        }

        /// <summary>
        /// 构造代理的方法
        /// </summary>
        /// <param name="classType">原类型</param>
        /// <param name="inspectorFieldBuilder">拦截器</param>
        /// <param name="typeBuilder">代理类型</param>
        private static void BuildMethod(Type classType, FieldBuilder inspectorFieldBuilder, TypeBuilder typeBuilder)
        {
            //获取原类型的所有方法信息
            var methodInfos = classType.GetMethods();
            //遍历所有的方法信息
            foreach (var methodInfo in methodInfos)
            {
                //如果不是虚方法和抽象放法,进入下一个
                if (!methodInfo.IsVirtual && !methodInfo.IsAbstract) continue;
                //如果是Object的ToString方法,进入下一个
                if (methodInfo.Name == "ToString") continue;
                //如果是Object的GetHashCode方法,进入下一个
                if (methodInfo.Name == "GetHashCode") continue;
                //如果是Object的Equals方法,进入下一个
                if (methodInfo.Name == "Equals") continue;

                //获取该方法的所有参数信息
                var parameterInfos = methodInfo.GetParameters();
                //用Lamada表达式获取每个参数的类型
                var parameterTypes = parameterInfos.Select(p => p.ParameterType).ToArray();
                //获取参数的个数
                var parameterLength = parameterTypes.Length;
                //获取方法是否有返回值
                var hasResult = methodInfo.ReturnType != VoidType;

                //创建和该方法一样的方法
                var methodBuilder = typeBuilder.DefineMethod(methodInfo.Name,
                                                             MethodAttributes.Public | MethodAttributes.Final |
                                                             MethodAttributes.Virtual
                                                             , methodInfo.ReturnType
                                                             , parameterTypes);
                //得到IL加载器
                var il = methodBuilder.GetILGenerator();

                //局部变量
                il.DeclareLocal(typeof(object)); //correlationState
                il.DeclareLocal(typeof(object)); //结果
                il.DeclareLocal(typeof(object[])); //参数

                //BeforeCall(string operationName, object[] inputs);前置通知
                il.Emit(OpCodes.Ldarg_0);

                il.Emit(OpCodes.Ldfld, inspectorFieldBuilder);//获取字段_inspector
                il.Emit(OpCodes.Ldstr, methodInfo.Name);//参数operationName

                if (parameterLength == 0)//判断方法参数长度
                {
                    il.Emit(OpCodes.Ldnull);//null -> 参数 inputs
                }
                else
                {
                    //创建new object[parameterLength];
                    il.Emit(OpCodes.Ldc_I4, parameterLength);
                    il.Emit(OpCodes.Newarr, typeof(Object));
                    il.Emit(OpCodes.Stloc_2);//压入局部变量2 parameters

                    for (int i = 0, j = 1; i < parameterLength; i++, j++)
                    {
                        //object[i] = arg[j]
                        il.Emit(OpCodes.Ldloc_2);
                        il.Emit(OpCodes.Ldc_I4, 0);
                        il.Emit(OpCodes.Ldarg, j);
                        if (parameterTypes[i].IsValueType) il.Emit(OpCodes.Box, parameterTypes[i]);//对值类型装箱
                        il.Emit(OpCodes.Stelem_Ref);
                    }
                    il.Emit(OpCodes.Ldloc_2);//取出局部变量2 parameters-> 参数 inputs
                }

                il.Emit(OpCodes.Callvirt, typeof(IInterceptor).GetMethod("BeforeCall"));//调用BeforeCall
                il.Emit(OpCodes.Stloc_0);//建返回压入局部变量0 correlationState

                //Call methodInfo
                il.Emit(OpCodes.Ldarg_0);
                //获取参数表
                for (int i = 1, length = parameterLength + 1; i < length; i++)
                {
                    il.Emit(OpCodes.Ldarg_S, i);
                }
                il.Emit(OpCodes.Call, methodInfo);
                //将返回值压入 局部变量1result void就压入null
                if (!hasResult)
                {
                    il.Emit(OpCodes.Ldnull);
                }
                else if (methodInfo.ReturnType.IsValueType)
                {
                    il.Emit(OpCodes.Box, methodInfo.ReturnType);//对值类型装箱
                }
                il.Emit(OpCodes.Stloc_1);

                //AfterCall(string operationName, object returnValue, object correlationState);
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, inspectorFieldBuilder);//获取字段_inspector
                il.Emit(OpCodes.Ldstr, methodInfo.Name);//参数 operationName
                il.Emit(OpCodes.Ldloc_1);//局部变量1 result
                il.Emit(OpCodes.Ldloc_0);// 局部变量0 correlationState
                il.Emit(OpCodes.Callvirt, typeof(IInterceptor).GetMethod("AfterCall"));

                //result
                if (!hasResult)
                {
                    il.Emit(OpCodes.Ret);
                    return;
                }
                il.Emit(OpCodes.Ldloc_1);//非void取出局部变量1 result
                if (methodInfo.ReturnType.IsValueType)
                {
                    il.Emit(OpCodes.Unbox_Any, methodInfo.ReturnType);//对值类型拆箱
                }
                il.Emit(OpCodes.Ret);
            }
        }

        /// <summary>
        /// 构造代理的构造函数
        /// </summary>
        /// <param name="classType">原类型</param>
        /// <param name="inspectorFieldBuilder">拦截器</param>
        /// <param name="typeBuilder">代理类型</param>
        private static void BuildCtor(Type classType, FieldBuilder inspectorFieldBuilder, TypeBuilder typeBuilder)
        {
            {
                //定义代理的构造函数
                var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis,
                                                                Type.EmptyTypes);
                //获得IL指令器
                var il = ctorBuilder.GetILGenerator();

                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Call, classType.GetConstructor(Type.EmptyTypes));//调用base的默认ctor
                il.Emit(OpCodes.Ldarg_0);
                //将typeof(classType)压入计算堆
                il.Emit(OpCodes.Ldtoken, classType);
                il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new[] { typeof(RuntimeTypeHandle) }));

                #region 创建并实例化拦截器
                //调用DefaultInterceptorFactory.Create(type)
                il.Emit(OpCodes.Call, typeof(DefaultInterceptorFactory).GetMethod("Create", new[] { typeof(Type) }));
                //将结果保存到字段_inspector
                il.Emit(OpCodes.Stfld, inspectorFieldBuilder);
                #endregion

                il.Emit(OpCodes.Ret);
            }
        }
    }
}

获得代理类使用就带上了前后日志服务

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace MyAop
{
    class Program
    {
        static void Main(string[] args)
        {
            Animal animal = DefaultProxyBuilder.CreateProxy<Animal>();
            animal.Speak();
            Console.WriteLine();
            animal.Speak("Hello");
            Console.ReadLine();
        }
    }
}

以上先要了解工厂模式,在用反射实现工厂模式的基础上结合反射发出实现代理模式就得到Spring的IOC和AOP的基础。后续将讲到居于Spring.Net企业级框架构造iMedicalLIS系统(使用控制反转IOC、切面编程AOP)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小乌鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值