关于动态代理

助409912936

助409912936

2016-02-19 18:50

有一种朋友不在生活里,却在生命力;有一种陪伴不在身边,却在心间。图老师即在大家的生活中又在身边。这么贴心的服务你感受到了吗?话不多说下面就和大家分享关于动态代理吧。
本来想上周末没能用DELPHI实现动态代理就算了,可是这几天却始终放不下这个想法,这实在是一个太美妙的想法了。而且在认真看了VCL对SOAP的实现后,现在至少有九成的把握可以实现这样一个动态代理。

  那么动态代理有什么用?

  这要先从GoF的Proxy模式说起。

  假设有下面这样一个接口及其实现:

  现在,如果你是这个接口的用户,而这个接口及其实现者提供了一个:

  Foo : IFoo;

  给你,其中Foo指向TFooImpl的一个实例。现在你有了IFoo的定义,和这个Foo实例--注意,你没有TFooImpl的定义和实现代码。如果现在要求你为所有的IFoo.doSth增加事务功能(假设doSth被实现为对数据库作更新操作),要怎么办?

  GoF的Proxy模式就是解决方案之一:

(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)

  如果所示,首先要实现一个新的IFoo接口实现--TStaticProxy。其中用了一个属性FImpl记录了TFooImpl的实例。然后在 TStaticProxy中实现doSth和bar,并且将不需要变更的bar函数直接委托给FImpl处理,而在doSth的实现里加入事务处理即可。 TStaticProxy的代码大致如下:

TStaticProxy = class( TInterfacedObject, IIFoo )private  FImpl : IFoo;public  constructor Create( aImpl : IFoo );  function doSth( ... ) : xxx;  function bar( ... ) : xxx;end;constructor TStaticProxy.Create( aImpl : IFoo );Begin  FImpl := aImpl;End;function TStaticProxy.doSth( ... ) : xxx;Begin  BeginTransaction;  Result := FImpl.doSth( ... );  EndTransaction;End;function TStaticProxy.bar( ... ) : xxx;Begin  Result := FImpl.bar( ... );End;

  然后,在所有需要用到Foo对象的地方,改用新的NewFoo对象,如下:

var  NewFoo : IFoo;Begin  NewFoo := TStaticProxy.Create( Foo ) As IFoo;  ...  //  之后就可以把NewFoo完全当作Foo一样使用了。End;

  可见,我们通过了一个Proxy类代理了所有对IFoo接口的操作,相当于在从IFoo到TFooImpl之间插入了自己的代码,在某种程度上,这就是AOP所谓的“横切”。当然如果你能有TFooImpl的代码的话,就简单了,只要如下:

  从TFooImpl派生一个TNewFooImpl,然后在其中Override一下TFooImpl中的doSth即可,然后就创建TNewFooImpl的实例来代替Foo引用即可。

  但问题就在于你必须拥用TFooImpl的代码,并且可以变更所提供的Foo实例,但这在很多时候是做不到的--除非不是用DELPHI,而是如 Python一类的动态语言^O^。比如组件容器,比如远程实例等。还有像“虚代理”(就是当创建FImpl代价很高时,就在创建时只创建代理类,然后在真正需要时才创建FImpl的实例)

  但上面这种静态代理还是很麻烦。首先,如果IFoo的成员函数很多的话,必须要一一为它们加上代理实现;其次,如果在应用中有很多接口需要代理时,就必须一一为它们写这样的专用代理类;第三,需要变更代理功能时,需要修改所有的代理类……

  特别是像组件容器或是通用远程代理这样,对要实现的接口并不能确定的情况下,静态代理一点用也没有。

  所以我们需要“动态代理”。我是在看了GIGIX发表在今年第一期《程序员》上的《动态代理的前世今生》一文后,虽然他说是的JAVA在 JDK1.3中提出的,在java.lang.reflect中的proxy。但这却让我突发奇想,发现其实完全可以在DELPHI里也实现这样一个动态代理。

  一个典型的动态代理如下:

  这样,我们只需要把要增加在功能做成一个IInvocationHandler接口的实例,如图中的TFooInvHandler。然后动态创建一个支持IFoo接口的TDynamicProxy的实例--它是一个动态代理,只需要传入相应的参数:要实现的接口和相应的InvHandler实例即可,不需要为每个接口写一个代理。当然如GIGIX文中所说,对于C++来说,这个可以用模板实现,但问题在于模板归根到底是一种编译时的动态化技术,对于组件容器这样需要运行时动态化的应用,它还是不能实现。最后,InvHandler通过RTTI去调用具体的实现Foo。

(本文来源于图老师网站,更多请访问https://m.tulaoshi.com/bianchengyuyan/)

  它的用法大致如下:

TFooInvHandler = class( TInterfacedObject, IInvocationHandler )private  FImpl : IFoo;public  constructor Create( aImpl : IFoo );  function Invoke( IID, MethodName, Args[] ) : xxx;end;constructor TFooInvHandler.Create( aImpl : IFoo );Begin  FImpl := aImpl;End;function TFooInvHandler.Invoke( IID, MethodName, Args[] ) : xxxBegin  If ( IID = IFoo ) AND ( MethodName = 'doSth' ) Then  Begin BeginTransaction; Result := DoInvoke( FImpl, IID, MethodName, Args[] ); EndTransaction;  End  Else Result := DoInvoke( FImpl, IID, MethodName, Args[] );End;var  Handler : IInvocationHandler;  NewFoo : IFoo;Begin  Handler := TFooInvHandler.Create( Foo );  NewFoo := TDynamicProxy.Create( TypeInfo(IFoo), Handler ) As IFoo;  ...  //  之后就可以把NewFoo完全当作Foo一样使用了。End;

  注意:其中IInvocationHandler接口我还没想好要怎么定义,所以这段代码只是大致说明一下问题。另外,其中的DoInvoke就是通过RTTI来调用FImpl的。

  从上面的代码可以看到,TDynamicProxy通过参数IFoo动态生成了一个对IFoo接口的代理,并且通过Handler参数插入一个处理接口IInvocationHandler,由TDynamicProxy把对IFoo接口的调用全部转成对IInvocationHandler接口的调用,最后由TFooInvHandler类来视情况处理。在这里,可以通过运行时配置方式来动态决定是否需要切入事务所处理,需要对哪个接口的哪个方法切入。

  有了这样一个动态代理,还可以很方便地在InvocationHandler里切入如安全性检查,LOG等。这样的话,用DELPHI来实现AOP也不成问题了。

  现在我面临的问题就是:如何来定义这个IInvocationHandler。

  其实这里最主要的问题就是参数的传递的问题。接口可以用IID表示,方法可以用方法名,但参数变化太多了:一是数量不确定,可以有任意多个参数;二是类型不确定;三是传值参数和引用参数的问题。如前面那个例子用的是简单的办法,就是用一个不定长的Variant数组来记录,可以解决前两个问题,但第三个问题就比较麻烦,难道要用一个Tuple来作返回值?太麻烦了吧。

  在VCL的SOAP实现里是通过一个TInvContext在记录的,但这样的话对于Handler的开发者来说,就不得不面对TInvContext的内部复杂性,易用性太差。

  这就是我现在还不能确定实现的那一成。-_-|||

展开更多 50%)
分享

猜你喜欢

关于动态代理

编程语言 网络编程
关于动态代理

关于.NET动态代理的介绍和应用简介

Web开发
关于.NET动态代理的介绍和应用简介

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

关于如何用Java动态代理实现AOP的技术说明

编程语言 网络编程
关于如何用Java动态代理实现AOP的技术说明

代理模式之Java动态代理实现方法

编程语言 网络编程
代理模式之Java动态代理实现方法

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

java 静态代理 动态代理深入学习

编程语言 网络编程
java 静态代理 动态代理深入学习

Java动态代理实现AOP

Java JAVA基础
Java动态代理实现AOP

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

Delphi中的布尔类型

Delphi中的布尔类型

东京巷尾绽放的薰衣草

东京巷尾绽放的薰衣草
下拉加载更多内容 ↓