现在位置:主页>资源共享> 文章内容

Delphi 中智能对象的实现

我要投稿更新日期:2008-07-22 点击:
回想一下,我们中的大部分都应该写过类似这样的代码吧:

  procedure TYourClass.SomeMethod(SomeParam: SomeType);
  var
    SomeObj: TSomeClass;
  begin
    SomeObj := TSomeClass.Create;
    try
      SomeObj.DoSomeThing(SomeParam);
    finally
      SomeObj.Free;
    end;
  end;

在一个方法(或过程、函数)中,你需要临时创建一个对象,在离开方法前,需要将其
释放掉。于是,我们一次又一次不厌其烦的写着这样的 try-finally-end 的代码。这时
我不由地羡慕起 C++ 程序员来,他们可以吧对象分配在栈上,离开作用域后,对象就会
自动释放,多方便啊:)

可惜,Delphi 中的对象都是分配在堆上的。要是 Delphi 中的对象也可以向 C++ 那样,
在方法中需要时临时创建,使用完了就不用管,离开方法时自动会被释放(无论是否出现
异常,这也很重要),那该多好啊。

但是,Delphi 没有直接提供这样的机制。不过我们还是有办法:)考虑一下,C++ 中的
智能指针是怎么回事?一个指针分配空间后,也像局部对象一样不管了,离开作用域后会
自动释放其分配的空间。实际上就是用了一个局部对象包裹之,在离开作用域之后,局部
对象自动释放,在其析构函数中释放那指针的空间。

那么,在 Delphi 中是否有类似的机制呢?其实是有的,Delphi 中的接口(Interface),
在离开(过程级的)作用域后,会自动释放(其实现对象),我们可在这上面做点文章。
在这里,就可以借用 C++ 中智能指针的思想,用可以自动释放的局部对象以释放特定的
指针;用可以自动释放的接口(的实现对象)以释放特定的对象。只要我们设法把一个需
要自动释放的对象的引用传到一个接口中,那么我们就可以在接口释放时,释放该对象。
关键就在于这个接口和需要自动释放的对象的生命周期应该一致。因为我们要自动释放的
对象是局部变量,这个接口也应该是一个局部变量。

在明确这一点后,实现就相对比较容易了,去掉空行和注释一共不到 40 行,呵呵。那么
先来个例子,看看这个东西是怎么用的,然后给出实现。

  program SafeObjTest;

  {$APPTYPE CONSOLE}

  uses
    SysUtils, XhSafeObj;

  type
    TTest = class
    private
      FName: string;
    public
      constructor Create(const Name: string);
      destructor Destroy; override;
      procedure SayHello;
    end;

  { TTest }

  constructor TTest.Create(const Name: string);
  begin
    FName := Name;
  end;

  destructor TTest.Destroy;
  begin
    Writeln(FName, ' is gone');

    inherited;
  end;

  procedure TTest.SayHello;
  begin
    Writeln('Hello, I am ', FName);
  end;

  procedure Proc1;
  var
    Test: TTest;
  begin
    Test := TTest.Create('Tom');
    SafeObject(Test);
    Test.SayHello;
  end;

  procedure Proc2;
  var
    Test: TTest;
  begin
    Test := TTest.Create('Jim');
    SafeObject(Test);
    Test.SayHello;
    raise Exception.Create('Something wrong');
    Test.SayHello;
  end;

  procedure Proc3;
  var
    Test: TTest;
  begin
    SafeCreateObject(TTest.Create('Jerry'), Test);
    Test.SayHello;
  end;

  begin
    Proc1;
    try
      Proc2;
    except
      Writeln('Catch you');
    end;
    Proc3;
    Writeln('Finished');
    Readln;
  end.

以下是这个例子的输出:

  Hello, I am Tom       // Tom 创建
  Tom is gone           // 在 Jim 创建之前,Tom 释放了
  Hello, I am Jim       // Jim 创建,这行只出现一次说明异常正确抛出
  Jim is gone           // 即使出现异常,Jim 还是释放了
  Catch you             // 而且是在退出 Proc2 之前
  Hello, I am Jerry     // 演示另一种用法
  Jerry is gone         // 再次成功 :-)
  Finished

以下是具体实现单元文件(XhSafeObj.pas):

{******************************************************************************}

上一页12 3 下一页
所有评论

评论列表


我也评论来评论! 点击此处参与本文评论

注意:本站采用匿名评论,请各位网友注意自己的言行