今天看了会刘艺写的<<Delphi面向对象编程思想>>
79页的
示例程序 3-10 Factory Method 模式下动态控件创建的进一步改进
有了点疑惑,代码贴出来,大家有时间看看
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls;type
TControlClass = class of TControl; TControlFactory = class
private
FControlObj: TControl;
public
constructor Create(AOwner: TWinControl; ControlClass: TControlClass);
end; TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
RadioGroup1: TRadioGroup;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;
ControlObj: TObject;implementation{$R *.dfm}procedure TForm1.FormCreate(Sender: TObject);
beginend;{ TControlFactory }constructor TControlFactory.Create(AOwner: TWinControl;
ControlClass: TControlClass);
begin
FControlObj := ControlClass.Create(AOwner);
FControlObj.Parent := AOwner;
FControlObj.Name := FControlObj.ClassName;
FControlObj.SetBounds(10, 10, 250, 150);
Self := TControlFactory(FControlObj);
end;procedure TForm1.Button1Click(Sender: TObject);
const
ControlClassArray: array[0..2] of TControlClass =
(TMonthCalendar, TMemo, TColorBox);
var
I: Integer;
begin
for I := 0 to ControlCount - 1 do
if (Controls[I] is TMonthCalendar) or (Controls[I] is TMemo)
or (Controls[I] is TColorBox) then
Controls[I].Free; ControlObj := TControlFactory.Create(Self,
ControlClassArray[RadioGroup1.ItemIndex]);
Label1.Caption := ControlObj.ClassName; if (ControlObj is TMemo) then TMemo(ControlObj).Lines.Add('测试成功!');
if (ControlObj is TColorBox) then TColorBox(ControlObj).ItemIndex := 2;
end;end.
疑惑的地方在TControlFactory的Create里
Self := TControlFactory(FControlObj);
我不知道是不是我好久没看delphi的缘故,这句我觉得这样写那TConrolFactory申请的这段内存的引用岂不是丢了
我觉得这产生内存的泄漏,而作者在这写这是比较绝妙的
我天生愚笨,没看懂,大家看一下.
79页的
示例程序 3-10 Factory Method 模式下动态控件创建的进一步改进
有了点疑惑,代码贴出来,大家有时间看看
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, ComCtrls;type
TControlClass = class of TControl; TControlFactory = class
private
FControlObj: TControl;
public
constructor Create(AOwner: TWinControl; ControlClass: TControlClass);
end; TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
RadioGroup1: TRadioGroup;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;
ControlObj: TObject;implementation{$R *.dfm}procedure TForm1.FormCreate(Sender: TObject);
beginend;{ TControlFactory }constructor TControlFactory.Create(AOwner: TWinControl;
ControlClass: TControlClass);
begin
FControlObj := ControlClass.Create(AOwner);
FControlObj.Parent := AOwner;
FControlObj.Name := FControlObj.ClassName;
FControlObj.SetBounds(10, 10, 250, 150);
Self := TControlFactory(FControlObj);
end;procedure TForm1.Button1Click(Sender: TObject);
const
ControlClassArray: array[0..2] of TControlClass =
(TMonthCalendar, TMemo, TColorBox);
var
I: Integer;
begin
for I := 0 to ControlCount - 1 do
if (Controls[I] is TMonthCalendar) or (Controls[I] is TMemo)
or (Controls[I] is TColorBox) then
Controls[I].Free; ControlObj := TControlFactory.Create(Self,
ControlClassArray[RadioGroup1.ItemIndex]);
Label1.Caption := ControlObj.ClassName; if (ControlObj is TMemo) then TMemo(ControlObj).Lines.Add('测试成功!');
if (ControlObj is TColorBox) then TColorBox(ControlObj).ItemIndex := 2;
end;end.
疑惑的地方在TControlFactory的Create里
Self := TControlFactory(FControlObj);
我不知道是不是我好久没看delphi的缘故,这句我觉得这样写那TConrolFactory申请的这段内存的引用岂不是丢了
我觉得这产生内存的泄漏,而作者在这写这是比较绝妙的
我天生愚笨,没看懂,大家看一下.
解决方案 »
- 请问 DSPack 如何实现 在 摄像头 录制 AVI 时 将 文字 叠加到 AVI 录像中 ???
- 请指点一下,讨论也可以,顶也有分
- 视频采集问题!求助加散分!
- *************************免费短信服务*******************************
- 请问在Delphi中调用Mapx控件时的问题
- 简单问题.
- 修改TQuery查询的结果,快进来看看!
- 用什么方法可以把文本中的指定内容导入到ACCESS数据库中!注意:
- 帮帮我,help
- 请教:怎样实现当一个richedit滚动时(包括键盘和拖动滚动条)另一个richedit同步滚动
- 有做过财务软件的高手哇,怎样把后坠为lst的报表文件导入excel?
- 请各位GG帮助,关于定义的问题
刘艺的口碑并不好,以前写的Midas的书就很烂,不客气的说是误人子弟。
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
他的第一个例子是用的类方法
这是第二个例子
书上的原话:
'更绝妙的是通过一条转型赋值语句,将动态创建的控件对象FContorlObj向上转型为
TControlFactory类型,并赋值给TControlFactory自身,由TControlFactory来传递,
这就使得TControlFactory有了七十二变的本事';
我看的晕晕乎乎的
----------------------------------------------
1、讲的对,示例程序3-10存在TControlFactory实例无法销毁,内存泄漏问题。
但TControlFactory的功能是创建其他实例(FControlObj),它所保存的唯一变量(FControlObj)只是一个实例的引用,不需要分配多少内存。所以可以不用考虑内存回收问题。
2、结合本书该部分的上下文,可以明显看出示例程序3-10的主要目的是来讲解和模拟构造函数的行为。
ControlObj:=TControlFactory.create(self,
ContrlClassArry[RadioGroup1.ItemIndex]);也是为了演示TControlFactory的构造函数不是返回它自己的实例,而是摇身一变返回动态创建控件的实例。这种打破常规的例子是为了加深读者对构造函数、self参数、转型赋值的理解,启发思路的意义甚于实用的意义。所谓“绝妙”是指这个例子产生的效果(构造函数返回的不是它自己的实例,而可以动态构造出一个任意的实例,即书中所说的“七十二变”。),而不是指程序本身。
严格地讲,示例程序3-10还不是一个真正的工厂方法模式,真正的工厂方法模式是前一例(示例程序3-9)
3、题外话:鉴于.net是有自动回收内存机制的,以后Delphi.net版本是不是不需要考虑内存回收问题了?看来自动回收内存机制是趋势。------------------------------------------------------------------------------
感谢xzgyb (老达摩)认真阅读拙作,提出这个问题。
感谢FrameSniper今天专门告诉我大家在这里提出疑问。
欢迎大家继续把发现的问题告诉我,以便以后再版时修订。
刘艺
www.liu-yi.net
但TControlFactory的功能是创建其他实例(FControlObj),它所保存的唯一变量(FControlObj)只是一个实例的引用,不需要分配多少内存。所以可以不用考虑内存回收问题。
/////////
这句话并没有正真的解决上边的疑惑,类工厂本身也只是一个类,用来创建其它实例,但是,以这这个例子的方法进行下去的话,感觉有些事倍功半,而且本身就已经有违于模式理念;
ControlClassArray: array[0..2] of TControlClass =
(TMonthCalendar, TMemo, TColorBox);
也就是可以直接使用 controlobj := ControlClassArray[i].Create(nil);至于作者认为其72变,可能是一时忘记了,delphi的所有类变量都是引用吧,既然是引用,当然可以使她指向任意的内存空间,所以这番手脚和下面代码无异
TControlFactroy controlfc;
controlfc 和 controlfc.self是相同的引用,改变self就等于改变了controlfc的引用地址啊
那么 self := TControlFactroy(...) 等同于 controlfc = TControlFactroy(...)换句话说,作者只是将类型转换放在其他地方做了而已。而这样做的代价就是引起了悬空的内存。代码的不严谨,和现在软件要求的便于理解背道而驰。另外,我认为写书和论坛是两回事,论坛可以随心所欲的发表自己的言论,大家来讨论。而写书必须承担责任,因为很多人会花费金钱和时间来读这本书。不成熟的、想当然的做法真的会误人子弟!这是我个人的想法,如果作者觉得我理解错误还请指出。
其实,这种情况下,我宁可在TControlFactory中多定义一个ControlObj的属性,然后多加一点代码,就可以了。
ControlObj:=TControlFactory.create(self, ContrlClassArry[RadioGroup1.ItemIndex]).ControlObj; //当然这样还是没有保存TControlFactory对象的实例此外,即便.net有GC了,但是为了效率问题,有时还是需要自己手工释放。所以.net中还是提供了IDisposable这个接口,还有using语句,专门用于手工释放资源。
如果不是孤立地看这段代码,而是联系书中这段上下文去理解的话,不难发现作者此处的良苦用心。其实,示例程序3-9就是一个无可挑剔的程序,很规范的工厂方法模式。远比chechy的解决方法好。可是作者又为何要冒内存泄漏的风险画蛇添足呢?(作者肯定知道会有内存泄漏。这一点我不怀疑)。我想无非是欲通过打破常规的思路演示修改构造函数的奇特效果。这一点在书中示例程序3-10之前就有详细的交代和铺垫。
当然,删掉这段代码对作者来说是很容易的。不过,至少我自己认为通过这段代码我理解了构造函数和self的作用,明白了构造函数隐式返回了self(这就是为什么叫构造函数,而不是叫构造方法)。以前,我编程很少敢在构造函数中作手脚,都是保守的写法TXXX.create;现在至少我会乐于做这方面的尝试。