介绍两个在DELPHI下支持接口的类

来源:互联网 发布:ubuntu 修改帐号密码 编辑:程序博客网 时间:2024/05/16 17:19

DELPHI虽然很好,但目前不流行,所以相关的资料相对比较少,以前我也是花了不少时间才有所得。

为了方便同行,有时间我会把一些经验在这里和大家分享。


用过的都知道,在DELPHI WIN32下使用接口会有点复杂。一般通过继承TInterfacedObject来实现接口,而TInterfacedObject子类实例是由DELPHI根据引用计数来自动管理释放的。稍不注意,很容易出现异常。


所以使用DELPHI的接口要注意以下事项:

1.当使用接口变量时,如:p:Interface,要注意p的生命期。

  在方法内部定义的p,方法执行结束时,p的生命期才算结束。

  定义全局的p,只有在应用退出时,p的生命期才算结束。

  在类内定义p作为属性,只有该类实例释放时,p才算用完。


  所以如果p引用的对象在p的生命期结束前就释放了,很容易出现一些莫名其妙的异常。

  当然,你在用完p后能 p:=nil,是一个好的习惯。

2.对于表达式: (对象 as 接口).方法(..)  ,可以认为DELPHI会产生一个局部的接口变量,所以如果对象在这局部范围退出前会被释放的话,退出局部范围时会触发异常。解决的办法是:p := 对象 as 接口,显式使用接口变量,用完就设为NIL。

3.尽量把接口作为参数。譬如:定义一过程 procedure  aaa(const p:Interface) ;,如果使用时是:aaa(TTestClass.Create(..)),那么肯定会导致内存泄漏。

4.TInterfacedObject及其子类的实例,在创建后若未赋值给任何接口变量,需要手动释放。



这里介绍两个类,或许对你有用。

1.TCommonInterfaced。继承它可以实现接口,特点是屏蔽DELPHI的自动管理,由开发人员来手动管理实例的释放。

2.TEventInterfaced。继承它可以实现接口,特点是在激活实例的自动释放功能后,实例会在外部用完时由DELPHI来释放;若没有激活自动释放功能,则手动释放。这个类主要用在事件模型下,类似于JAVA的事件模型,监听器是以接口形式挂在事件源上的,只有当事件源撤销后,监听器才能释放。所以,如果监听器是继承自 TEventInterfaced,那么事件源在撤销前激活监听器的自动释放功能,那么DELPHI就能选择适当的时机释放监听器了。



源代码如下:


********************************************************************

unit euBase;


interface
uses Classes,SysUtils ;


Type
 
  //普通的接口对象。当接口不再使用时不会自动释放对象。
  TCommonInterfaced = class(TInterfacedObject)
  protected
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
  end;

   //专用在事件模型的接口对象。
   //所以当需要释放实现接口的对象时,只要激活接口的自动释放功能,对象就会在不使用接口时自动释放
  IEventInterface = interface(IInterface)
    ['{4A8C144E-07B9-4357-8BF0-EE57D2F69888}']
    procedure ReleaseInIdle;
  end;

  {
  专用在事件模型的接口对象。
  当需要释放实现接口的对象时,只要激活接口的自动释放功能,
  对象就会在不使用接口时自动释放。
  }
  TEventInterfaced = class(TInterfacedObject, IEventInterface)
  private
    mAutoRelease: Boolean;
    procedure ReleaseInIdle;
  protected
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  public
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
  end;
 
 

implementation

{ TCommonInterface }

{
****************************** TCommonInterfaced *******************************
}
procedure TCommonInterfaced.AfterConstruction;
begin

end;

procedure TCommonInterfaced.BeforeDestruction;
begin
 
end;

function TCommonInterfaced._AddRef: Integer;
begin
  Result:=1 ;
end;

function TCommonInterfaced._Release: Integer;
begin
  Result:=1 ;
end;

{ TEventInterface }

{
******************************* TEventInterfaced *******************************
}
procedure TEventInterfaced.AfterConstruction;
begin
  inherited;
  mAutoRelease:=false ;
end;

procedure TEventInterfaced.BeforeDestruction;
begin
  inherited;
 
end;

procedure TEventInterfaced.ReleaseInIdle;
begin
  mAutoRelease:=true ;
end;

function TEventInterfaced._AddRef: Integer;
begin
  if (RefCount=0) and (mAutoRelease=false) then  Inherited _AddRef() ;
  Result:=Inherited _AddRef() ;
end;

function TEventInterfaced._Release: Integer;
begin
  if (RefCount=2) and (mAutoRelease=true) then
  begin
     Inherited _Release() ;
     Result:=Inherited _Release() ;
  end
  else if (RefCount<>1) or (mAutoRelease=true) then
     Result:=Inherited _Release()
  else
     Result:=Inherited _Release() ;
end;

end.


*******************************************************************

USE的单元可能需要补充,因为源代码是摘录的。

 
原创粉丝点击