代码改变世界

代理模式

2017-11-24 16:02  李明成  阅读(354)  评论(2编辑  收藏  举报

代理模式的意图:为其他对象提供一种代理以控制对这个对象的访问;定义蛮简单的,不好理解,那就联想下现实生活中的代理(委托人),比如生产上生产了不错的产品,可是生产商优势不在于营销呀,就请个代理商吧,我定个价格,你来营销,卖高价是你们的本事。这就是代理模式。  

  1. 代理分为 静态代理 和动态代理。静态代理方式是为每个被代理的对象构造对应的代理类,例如我们有一个计算器的接口以及具体的实现:
       public interface ICalculator
        {
            int Add(int a ,int b);
        }
    
        /// <summary>
        /// 计算器 根据输入 标准的输出计算结果
        /// </summary>
        public class CalculatorImpl : ICalculator
        {
            public int Add(int a, int b)
            {
                return a + b;
            }
        }
    
    /// <summary>
        /// 计算器代理类 在调用计算器执行之前或之后干点其他事
        /// </summary>
        public class CalculatorProxy : ICalculator
        {
            private CalculatorImpl _calculatorImpl;
            public CalculatorProxy(CalculatorImpl calculator)
            {
                _calculatorImpl = calculator;
            }
    
            public int Add(int a, int b)
            {
                //具体执行前可以做的工作
                Console.WriteLine("do this before");
                var result = _calculatorImpl.Add(1, 2);
                //具体执行后可以做的工作
                Console.WriteLine("do this after");
                return result;
            }
        }

    输出

    do this before
    do this after
    3

    这种方式看上去非常直接,实现也比较方便,不过存在一个问题,

    即如果需要对多个类型进行代理,并且在代理类中的功能实现是一致的。

    那么我们就需要为每一个具体的类都完成一个代理类,然后重复第写很多类似的代码---这会非常麻烦。

      使用代理可以帮助我们接触这种麻烦。动态代理是动态地生成具体委托类的

    代理类实现对象。不需要为各个委托类逐一实现代理类,只需药为一类代理行为写一个具体的实现类即可。

  2. 动态代理

    我们使用Autofac 结合Castle DynamicProxy 来实现.DynamicProxy2 是Castle项目核心的一部分,提供一种方法拦截框架.Autofac.Extras.DynamicProxy 集成包可以让在Autofac组件的方法调用被其他组件拦截。常见的使用场景如:事务处理、日志记录、安全控制等.

    根据官网教程 使用拦截基本步骤:

    l 创建拦截器

    使用autofac 注册拦截器

    l 启用类型拦截

    l 将拦截器与要拦截的类型关联

    我们接着使用上面计算器的例子.使用 nuget 安装:AutofacAutofac.Extras.DynamicProxy 

    • 创建拦截器
      /// <summary>
          /// 日志拦截器 实现  Castle.DynamicProxy.IInterceptor 接口
         /// </summary>
         public class LogInterceptor:IInterceptor
          {
             public void Intercept(IInvocation invocation)
             {
      
                 Console.WriteLine("do this before");
                 invocation.Proceed();
                 Console.WriteLine("do this after");
             }
          }
    • 使用autofac注册拦截器
      //类型注册    
                  builder.Register(c => new LogInterceptor());

      tip:你可以使用named方式进行注册如:

      builder.Register(c => new CallLogger(Console.Out)) .Named<IInterceptor>("log-calls");
    • 启用类型拦截
      //启用拦截器
                  builder.RegisterType<CalculatorImpl>().As<ICalculator>().EnableInterfaceInterceptors();

       tip:还可以使用EnableClassInterceptors扩展注册,这两种方法字面意思:创建一个执行拦截器的接口代理和动态子类的目标组件执行拦截的虚拟方法。注意virtual

    • 讲拦截器与要拦截的类型关联
       [Intercept(typeof(LogInterceptor))]
          public class CalculatorImpl : ICalculator
          {
              public int Add(int a, int b)
              {
                  return a + b;
              }
          }

       tip:初了使用特性标注的方式 ,还可以使用InterceptedBy()去注册扩展如:builder.RegisterType<SomeType>() .EnableClassInterceptors() .InterceptedBy(typeof(CallLogger));

      测试结果和调用代码

  3. 结构图与参与者

    • Proxy—保存一个引用使得代理可以访问实体,也叫做委托类、代理类,它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作
    • subject—定义RealSubject和Proxy的共用接口,这样就在任何使用realSubject的地方都可以使用Proxy
    • realsubject—定义proxy所代表的实体