1、 自动生命周期的整理
unit mtReaper;
interface type ImtReaper = interface ['{F3E97960-3F35-11D7-B847-001060806215}'] end;
TmtReaper = class(TInterfacedObject, ImtReaper) private FObject: TObject; public constructor Create(AObject: TObject); destructor Destroy; override; end;
implementation
uses SysUtils;
constructor TmtReaper.create(AObject: TObject); begin FObject := AObject; end;
destructor TmtReaper.Destroy; begin FreeAndNil(FObject); inherited; end;
end.
===================================================================== unit frmMain;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type TNoisyDeath = class(TObject) public destructor Destroy; override; end;
TForm1 = class(TForm) Button1: TButton; Button2: TButton; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private procedure WaitAWhile; public { Public declarations } end;
var Form1: TForm1;
implementation uses mtReaper; {$R *.dfm}
destructor TNoisyDeath.Destroy; begin showMessage('对象销毁了!'); inherited; end;
procedure TForm1.WaitAWhile; var i: Integer; begin for i := 0 to 5000 do begin caption := Inttostr(i); end; end;
procedure TForm1.Button1Click(Sender: TObject); var NoisyDeath: TNoisyDeath; begin NoisyDeath := TNoisyDeath.create; try waitAWhile; finally NoisyDeath.Free; end;
end;
procedure TForm1.Button2Click(Sender: TObject); var NoisyDeath: TNoisyDeath; girm: ImtReaper; begin NoisyDeath := TNoisyDeath.create; girm := TmtReaper.Create(NoisyDeath); waitAWhile; end;
end. |
Decorator模式
·在不影响其他对象的情况下,以动态、透明度的方式给单个对象添加职责
·处理那些可以撤消的职责
·当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;另一种情况可能是,因为类定义被隐藏,或类定义不能用于生成子类。
自动恢复字体
unit uSnapshot;
interface
uses SysUtils, mtReaper,classes;
type ISnapshot=interface ['{FA256FA8-211F-462D-890B-FC0EB6096AD8}'] procedure Restore; end;
TSnapshot=class(TInterfacedObject,ISnapshot) private FOriginal:TPersistent; FTarget:TPersistent; FReaper:ImtReaper; public constructor Create(Target:TPersistent); destructor Destroy;override; procedure Restore; end;
implementation
constructor TSnapshot.create(Target:TPersistent); begin FOriginal:=TPersistent(Target.classType.create); FReaper:=TmtReaper.create(FOriginal); FTarget:=Target; FOriginal.Assign(Target); end;
destructor TSnapshot.Destroy; begin restore; Inherited; end;
procedure TSnapshot.Restore; begin if FTarget<>nil then FTarget.Assign(FOriginal); end; end. unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls;
type TForm1 = class(TForm) FontDialog1: TFontDialog; btnSet: TButton; Memo1: TMemo; procedure btnSetClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure WaitAWhile; private public { Public declarations } end;
var Form1: TForm1;
implementation
uses uSnapshot;
{$R *.dfm}
procedure TForm1.btnSetClick(Sender: TObject); var FontSnapshot: ISnapshot; begin FontSnapshot := TSnapshot.Create(Memo1.Font); {这里可以填写可能会改变TFont状态的任何代码} if FontDialog1.Execute then Memo1.Font := FontDialog1.Font; Memo1.Update; WaitAWhile; end;
procedure TForm1.FormCreate(Sender: TObject); begin Memo1.Lines.Add( '一个模拟对象状态改变后自动恢复的例子。'); end;
procedure TForm1.WaitAWhile; var i: Integer; begin for i := 0 to 5000 do begin caption := '状态恢复倒计时:' + Inttostr(5000 - i); end; end;
end. |
这个例子确实有点份量,说明一些问题。
2、 TObject 类
1. inheritsFrom 判断一个类是否另一类的祖先类 2. 下面三种方案是分别运行的。 procedure TForm1.onclick(Sender: TObject); var str: string; tmpclass: TObject; classref: TClass; begin ///第一种最简单的解决方案 str := ''; ListBox1.Items.Add(str); str := format('Class Name = %s', [sender.ClassName]); ListBox1.Items.Add(str); str := format('Class Parent = %s', [sender.ClassParent.ClassName]); ListBox1.Items.Add(str); str := format('InstanceSize = %d', [sender.InstanceSize]); ListBox1.Items.Add(str);
//以下为第二种,复杂的解决方案 tmpclass := sender; while tmpClass.ClassParent <> nil do begin str := tmpclass.ClassName; listbox1.Items.Add(str); tmpclass := tmpclass.ClassParent.Create; end;
{方案三} listbox1.Items.Add('============================'); classref := sender.ClassType; while classref <> nil do begin listbox1.Items.Add(classref.ClassName); classref := classref.ClassParent; end; end; |
3、 TPersistent类
1.TPersistent类在Delphi类中的地位不亚于TObject类,该类定义于Classes单元中,Delphi中定义的类几乎都是由该类派生而来的。TPersistent之所以在Delphi类中居于如此重要的地位是因为它是Delphi可视化编程的基础。该类实现了对象公布(published)属性的存取,即在该类及其派生类中声明为published的属性、方法和事件等可在设计期时显示在Object Inspector窗体或数据模块的DFM 文件中。当Delphi 重新打开原来保存的窗口时,对象的设置值将被Delphi从DFM文件中读出。在程序运行期,对象将被初始化为设计期所设置的状态。 2. {$M+}
TPersistent = class(TObject) private procedure AssignError(Source: TPersistent); protected procedure AssignTo(Dest: TPersistent); virtual; procedure DefineProperties(Filer: TFiler); virtual; function GetOwner: TPersistent; dynamic; public destructor Destroy; override; procedure Assign(Source: TPersistent); virtual; function GetNamePath: string; dynamic; end;
{$M-}
{$M+}与{$TYPEINFO ON}作用是一样的, {$M-}与{$TYPEINFO OFF}作用是一样的。 当一个类在{$M+}和{$M-}间声明时,程序编译器将为类生成与RTTI(Runtime Type Information)相关的代码和事件也具有存取特性。如果一个类或祖先类都没有在{$M+}和{$M-}中声明,则该类不能在published的属性、事件和方法。
3. TPersistent的Assign方法,主要完成两个对象属性的复制,完成对象的published属性、方法和事件的逐个复制。 Assign方法在TPersistent类中声明为虚方法,以便允许每个派生类定义自己的复制对象方法。如果派生类没有重写Assign方法,则TPersistent的Assign方法会将复制动作交给源对象来进行: procedure TPersistent.Assign(Source: TPersistent); begin if Source <> nil then Source.AssignTo(Self) else AssignError(nil); end;
TPersistent的Assign方法很少被派生类所覆盖,但AssignTo却常被派生类根据需要覆盖。 如果由AssignTo方法来实现复制,那么必须保证源对象的类已经重写了AssignTo方法,否则将会抛出一个AssignError异常。 procedure TPersistent.AssignTo(Dest: TPersistent); begin Dest.AssignError(Self); end;
procedure TPersistent.AssignError(Source: TPersistent); var SourceName: string; begin if Source <> nil then SourceName := Source.ClassName else SourceName := 'nil'; raise EConvertError.CreateResFmt(@SAssignError, [SourceName, ClassName]); end;
Assign方法和AssignTo方法常用于对象的克隆。
4. function GetNamePath: string; dynamic; GetNamePath方法是Delphi内部调用的,用于取得对象名以显示在Object Inspector中。 function GetOwner: TPersistent; dynamic; ================================================= function TPersistent.GetOwner: TPersistent; begin Result := nil; end; =================================================
GetOwner用于返回对象的所有者,它往往和GetNamePath一起使用,GetOwner在TPersistent中只返回nil,该方法在TPersistent类中声明而不是在TComponent类中声明,是为了使一些由TPersistent派生的类可以在Object Inspector 中显示出来,如TCollection等类。对于一般应用程序设计来说,不需要直接调用这两个方法。
5. DefineProperties procedure DefineProperties(Filer: TFiler); virtual; 在TPersistent中声明的DefineProperties方法为非published属性存取提供了接口。对于从TPersistent派生的子类,Delphi编译器在编译时自动为类的published的属性加入与存取相关的代码,而对于其他的非published的属性要存入DFM文件或流中;需要在派生类中覆盖DefineProperties方法来完成这些属性值的存取操作。 |