网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > Delphi
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
本月文章推荐
.能够处理任何数据库字段的Panel.
.一种利用EXCEL快速写SQL语句的方.
.一名Delphi程序员的开发习惯(非.
.资源文件的应用.
.Delphi中动态链接库(DLL)的建立和.
.动态加载和动态注册类技术的深入.
.界面(FORM)自动生成工具.
.字符串函数大全.
.数据表的二维表存储及定位.
.firebird嵌入式数据库.
.用DELPHI给OICQ动手术(一).
.Delphi的Hint(2).
.Delphi程序执行时实时生成报表.
.类似网络蚂蚁的悬浮窗体.
.用Delphi2005和DUnit搭建敏捷开发.
.delphi的面向对象之路1.
.防止全局hook入侵Delphi版,2000.
.如何将C/C++程序转译成Delphi(十).
.Delphi开发单机瘦数据库程序要点.
.从实作标题栏按钮开始浅谈组件的.

两种Delphi实现Singleton模式方法

发表日期:2006-2-4


 

两种Delphi实现Singleton模式方法

haozi


摘  要 本文描述了两种Singleton模式的Delphi实现方式,并做了对比分析。
关键字 设计模式,Singleton

Singleton(单件)模式是一种很有用的设计模式。它的意图的是:仅仅创建一个类的实例,并提供一个访问它的全局访问点。全局变量使的一个对象易被访问,但不能防止你实例化多个对象。单件模式的目的就是确保在程序的生命周期内只有一个实例存在。
看下面的代码:
procedure TForm1. Button1Click(Sender: TObject);
var  lS1 : TSingleton;  l
S2 : TSingleton;
begin
  try    lS1 := TSingleton.Create;   ////调用类的构造器   
    lS2 := TSingleton.Create;   ////调用类的构造器 
    //// ...别的代码 
  finally
    lS1.Free;  ////释放对象
    lS2.Free;  ////释放对象
  end;
end;

在上面的代码中第一次调用Create函数时TSingleton类被实例化,lS1指向一个内存存放对象的地址,当第二次调用TSingleton.Create函数时又重新实例化了TSingleton对象,lS2指向内存分配的另一个地址。Singleton模式就是让类自己负责保存他的唯一实例。

在上面的代码中就是让lS2创建的时候也指向lS1指向的对象(也就是被分配同一个内存地址),同样我们在释放lS1时必须防止内存被释放,因为单件对象还被lS2所引用。从而保证在程序的生命周期内有且只有一个类实例。
 《设计模式》C++的示例代码是使用C++的静态成员变量保存实例的,同时使用protected的构造器函数。但是在Delphi中由于没有静态成员变量,所以不能原样的使用该单件模式示例的方法。以下我们分析两种DELPHI实现Singleton模式的几种方法。

一.基于override两个Tobject虚拟函数的方法

class function NewInstance: TObject; virtual;
procedure FreeInstance; virtual;
NewInstance函数负责类对象创建的时候为对象分配内存,FreeInstance则相反释放内存


前者在对象构造时调用,后者在对象析构时调用。
我们使用两个全局变量来保存单件对象和对象的引用记数。
var  Instance  : TSingleton  = nil;
     RefCount : Integer     = 0;

TSingleton类的单元:
////---------------------------------------------------------------------------

////
unit uSingleton;

interface

type
  TSingleton = class(TObject)
  public
    class function NewInstance: TObject; override; ////覆盖基类函数
    procedure FreeInstance; override;              ////覆盖基类函数
    class function RefCount: Integer; ////返回当前引用记数
  end;

//// Declaration global variables
var
  Instance: TSingleton = nil;
  RefCount: Integer = 0;

implementation

{ TSingleton }

procedure TSingleton.FreeInstance;
begin
  Dec( RefCount );   ////减少引用记数
  if ( RefCount = 0 ) then  ////是否为0,是则释放内存
  begin
    Instance := nil;
//// 释放单件类的私有变量
////…
    inherited FreeInstance;
  end;
end;

class function TSingleton.NewInstance: TObject;
begin
  if ( not Assigned( Instance ) ) then
  begin
    Instance := TSingleton(inherited NewInstance);
    ////初始化私有变量 例子:
    ////   Instance.VariableName := Value;
  end;
  Result := Instance ;
  Inc( RefCount );
end;

class function TSingleton.RefCount: Integer;
begin
  Result := RefCount;
end;

end.
////---------------------------------------------------------------------------

////


当调用TSingleton的构造器的时候,会调用我们override的NewInstance函数,由NewInstance分配内存并返回给构造器,这样通过override的NewInstance函数我们确保了Create函数只可能实例化一个TSingleton对象(无论调用多少次Create只返回第一次分配的内存地址)。同时RefCount变量保存我们有几个到对象的引用。

我们在来看测试代码

procedure TForm1.Button1Click(Sender: TObject);
var
  lS1, lS2: TSingleton;
  Ob1, Ob2: Tobject;
begin
 lS1 := TSingleton.Create;
  ShowMessage(IntToStr(RefCount)); //// Ref_Count = 1
  lS2 := TSingleton.Create;
  ShowMessage(IntToStr(RefCount)); //// Ref_Count = 2
  Ob1 := TObject.Create;
  Ob2 := Tobject.Create;
  if lS1 = lS2 then
    ShowMessage('地址相等') //// lS1 = lS2
  else
    ShowMessage('地址不相等');
  if Ob1 = Ob2 then
    ShowMessage('地址相等')
  else
    ShowMessage('地址不相等'); //// Ob1 <> Ob2
end;
当程序调用析构器的时候(就是调用FREE函数的时候),析构器会调用FreeInstance函数释放被构造器分配的内存。Override的FreeInstance函数保证引用记数为零的时候才释放单件模式对象的内存。
下面是我们的测试代码:
var
  lS1 : TSingleton;
  lS2 : TSingleton;
begin
 try
    lS1 := TSingleton.Create;   ////调用类的构造器
    lS2 := TSingleton.Create;   ////调用类的构造器
  //// ...别的代码
  finally
    lS1.Free;  ////这里会首先调用我们覆盖定义的FreeInstance,
              ////由于这时RefCount在减1后为1,单件对象没有被释放
    lS2.Free;  ////dec(RefCount)= 0 释放单件对象
  end;
end;

上面这种单件模式实现方法很好地实现了由类自身来负责保存自己的唯一实例(通过截取创建新对象的请求——参考《设计模式》。它对TSingleton类的使用没有特殊的限制——程序员可以随意的调用Create和Free函数。
本模式的缺点是:该TSingleton类不能作为父类继承生成子类。如果继承生成两个子类,Create时只产生一个对象。
procedure TForm1.Button1Click(Sender: TObject);
var
  lS1 : 子类一;
  lS2: 子类二;
begin
  lS1 := 子类一.Create;
  lS2 := 子类二.Create;  ////不会创建子类二,lS2将指向lS1指向的内存,
                        ////也就是  lS1 = lS2end;

二.《设计模式》上示例的Delphi实现
 《设计模式》的实现示例是通过私有构造器函数来实现控制只产生一个对象实例。但该给出的C++代码实现未给出对象如何释放。Delphi里面不能实现Create函数的私有化,我们新定义一个函数来代替Create函数,同时屏蔽父类的Create函数。代码如下


////---------------------------------------------------------------------------

////
unit uSingletonUnit;

interface
uses
  Classes, SysUtils;
type

  TCSingleton = class(TComponent)  ////从Tcomponent类继承来。
  private
constructor CreateInstance(AOwner: TComponent); ////传递Owner参数
//// 这样TCSingleton类对象就会随Owner一起销毁(拥有者负责销毁TCSingleton对象)
  public
    constructor Create(AOwner: TComponent); override;
    class function Instance(AOwner: TComponent): TCSingleton;
  end;

var
  gCSingleton: TCSingleton;  //// Global variables

implementation

{ TCSingleton }

constructor TCSingleton.Create(AOwner: TComponent);
begin
////屏蔽Create函数的功能
  raise Exception.CreateFmt('Access class %s through Instance only',
    [ClassName]);
end;

constructor TCSingleton.CreateInstance(AOwner: TComponent);
begin
  ////新定义的构造函数Private型的
  inherited Create(AOwner);
end;

class function TCSingleton.Instance(AOwner: TComponent): TCSingleton;
begin
  if not Assigned(gCSingleton) then
    gCSingleton := TCSingleton.CreateInstance(AOwner);
  Result := gCSingleton;
end;

end.
////--------------------------------------------------------------------------/

/
上面的实现类使用过程中,程序员不用考虑单件模式对象的销毁问题。只是不能调用Create,必须调用Instance函数来获得对象的实例,同时把单件拥有者作为参数传递到函数里。这种实现方法可以作为基类被继承,用在状态模式的单件里(参见参考文献4),实现执行时的多态。
三.结束语

Singleton 模式的Delphi实现在网上还能查着其他的一些实现方式,本文的两种方法上

最常见的和简单的。同时其它方法的思路也很跟以上两方法很相似。

上一篇:Delphi中关于TApplication类的详解 人气:4636
下一篇:SGIP的delphi原码 人气:3929
浏览全部Delphi的内容 Dreamweaver插件下载 网页广告代码 祝你圣诞节快乐 2009年新年快乐