`
tibaloga
  • 浏览: 873211 次
文章分类
社区版块
存档分类
最新评论

关于用Delphi实现动态代理

 
阅读更多
<!--StartFragment -->本来想上周末没能用DELPHI实现动态代理就算了,可是这几天却始终放不下这个想法,这实在是一个太美妙的想法了。而且在认真看了VCL对SOAP的实现后,现在至少有九成的把握可以实现这样一个动态代理。

那么动态代理有什么用?

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

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

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

  Foo : IFoo;

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

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

如果所示,首先要实现一个新的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。

它的用法大致如下:

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[] ) : xxx
Begin
  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的内部复杂性,易用性太差。

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

猛禽 Feb.03-05

分享到:
评论

相关推荐

    delphi实现代理服务器源码

    delphi实现代理服务器源码,delphi实现代理服务器源码

    Delphi实现IE_代理服务器设置程序

    Delphi实现IE_代理服务器设置程序

    proxy.rar_delphi Proxy_proxy server_代理 delphi_代理服务器

    用delphi编写设计一款自己的代理服务器软件,实现思路:当前流行的浏览器的系统选项中有一个参数,即“通过代理服务器连接”,经过编程测试,当局域网中一台工作站指定了该属性,再发出Internet请求时,请求数据将...

    用Delphi2010 实现邮件附件收发功能

    用Delphi2010 实现邮件附件收发功能 TIdPOP3组件简介 TIdPOP3 是用来接收邮件服务器的邮件信息到用户端的一个组件。它实现了RFC 1939协议。 在使用TIdPOP3组件时需设置它的几个成员属性。 Host :指定邮件服务器,...

    Delphi使用TIdFtp控件实现FTP协议

    Delphi使用TIdFtp控件实现FTP协议

    CGlib动态代理的好例子!

    一个用CGlib实现Java动态代理的简单、完整的好例子!

    proxy.rar_delphi Proxy_delphi 网络代理_proxy delphi_代理服务器

    一个代理服务器程序,主要功能是通过代理服务器来过滤网络信息,只实现了http部分,本源码主要是为代理服务器的设计提供一个思路 。运行本程序之前需要先在浏览器中设置相应的代理服务器地址和端口,端口号默认为998...

    delphi毕业设计之货运代理管理系统

    delphi毕业设计之货运代理管理系统!!!!

    用Delphi设计自己的代理服务器

    摘要:Delphi源码,网络相关,代理服务器 用delphi编写设计一款自己的代理服务器软件,实现思路:当前流行的浏览器的系统选项中有一个参数,即“通过代理服务器连接”,经过编程测试,当局域网中一台工作站指定了该...

    Delphi6分布式开发

    1.5 用delphi进行分布式应用程序的开发 1.5.1 delphi 6支持的分布式组件技术 1.5.2 开发midas应用 1.5.3 开发分布式web技术 第二篇 delphi 6的 comidcom/com十编程 第 2章 delphi 6的 com编程基础 ...

    远程桌面实现(C++&&Delphi)源码

    远程控制软件代码示例,编写远程控制软件要用到,此是修正版本的远程桌面传输程序,基于分块和隔行扫描原理,DELPHI和C++都用到了,有需要的研究一下。

    Delphi网络通信协议分析与应用实现pdf清晰

    4.5.2 IE中使用代理服务器设置 4.5.3 建立工程项目 4.5.4 关键代码分析 第5章 Telnet高级编程 5.1 Telnet简介 5.2 使用Windows的Telnet程序登录远程服务器 5.3 深入Telnet协议 5.3.1 NVT ASCII字符集 5.3.2 ...

    delphi获取设置禁用IE代理.rar_IE代理_禁用_获取_设置

    delphi编程实现获取、设置、禁用IE浏览器所使用的代理

    http代理服务器 轻松实现所需功能

    一个简单的http代理程序 能够实现对服务器端的过滤以及对URL的过滤

    delphi网络应用

    可以让多个局域网的计算机通过该代理上网)11.Webserver(Web服务器程序,运行该程序可以建立自己的网页服务器)12.telnet(实现了远程登录的客户端功能,使用它可以上BBS)13.TelnetProxy(实现了telnet代理服务器...

    Delphi模式编程第一分卷

    5.3.1 用抽象工厂模式动态构造界面风格 5.3.2 WebSnap的Web Module架构与抽象工厂模式 5.3.3 范例小结 第6章 建造者模式(Builder) 6.1 模式解说 6.2 结构和用法 6.2.1 模式结构 6.2.2 代码模板 6.3 范例与...

    Delphi模式编程第二分卷

    5.3.1 用抽象工厂模式动态构造界面风格 5.3.2 WebSnap的Web Module架构与抽象工厂模式 5.3.3 范例小结 第6章 建造者模式(Builder) 6.1 模式解说 6.2 结构和用法 6.2.1 模式结构 6.2.2 代码模板 ...

    Delphi点对点语音聊天.rar

    Delphi语音聊天程序,此类参考代码不多,很多都是网络传统聊天,发送文字和图片的,这一个是语音聊天程序,iphone2文件夹下是ip Phone 1.01 点到点语音电话软件的源码,自带反向回传语音代理服务,可以使两个不同...

    Delphi 深度探索(第二版)〖含随书光盘源代码〗

    6.1 使用delphi实现设计模式 6.1.1 工厂模式 6.1.2 单例模式(singleton) 6.1.3 建造模式(builder) 6.1.4 原型模式(prototype) 6.2 结构模式 6.2.1 适配器模式(adapter) 6.2.2 合成模式...

    学生管理系统Delphi7.0+SQL Sever

    程序、数据库、文档 学生信息管理和成绩管理 分为管理员、教师、学生三用户: 系统管理员 数据录入:用户、学生、班级信息录入   数据操作: 用户、学生、班级信息操作(查询、编辑)、课程信息查询、成绩信息查询...

Global site tag (gtag.js) - Google Analytics