看<>的一点疑惑

xzgyb 2003-10-28 01:23:48
今天看了会刘艺写的<<Delphi面向对象编程思想>>
79页的
示例程序 3-10 Factory Method 模式下动态控件创建的进一步改进
有了点疑惑,代码贴出来,大家有时间看看


unit Unit1;

interface

uses
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);
begin

end;

{ 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申请的这段内存的引用岂不是丢了
我觉得这产生内存的泄漏,而作者在这写这是比较绝妙的
我天生愚笨,没看懂,大家看一下.
...全文
58 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
chechy 2003-10-29
  • 打赏
  • 举报
回复
如果说,只有一点点内存造成泄漏,无所谓,那么我觉得太不严谨了。学术上应该讲究严谨。
其实,这种情况下,我宁可在TControlFactory中多定义一个ControlObj的属性,然后多加一点代码,就可以了。
ControlObj:=TControlFactory.create(self, ContrlClassArry[RadioGroup1.ItemIndex]).ControlObj; //当然这样还是没有保存TControlFactory对象的实例

此外,即便.net有GC了,但是为了效率问题,有时还是需要自己手工释放。所以.net中还是提供了IDisposable这个接口,还有using语句,专门用于手工释放资源。
ColdWolf 2003-10-29
  • 打赏
  • 举报
回复
to:newdream(newdream)

我一再仔细的看了这段程序,大概的明白了程序的用意。不过首先我觉得这代码至少不应该放在工厂模式进行讨论。

而且我觉得这个技巧除了产生了一段悬空的内存外,没有任何意义。反倒比直接使用类型麻烦,工厂的意义就是要隐藏实现,而这段代码已经知道了所有的实现:
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(...)

换句话说,作者只是将类型转换放在其他地方做了而已。而这样做的代价就是引起了悬空的内存。代码的不严谨,和现在软件要求的便于理解背道而驰。

另外,我认为写书和论坛是两回事,论坛可以随心所欲的发表自己的言论,大家来讨论。而写书必须承担责任,因为很多人会花费金钱和时间来读这本书。不成熟的、想当然的做法真的会误人子弟!这是我个人的想法,如果作者觉得我理解错误还请指出。
ihihonline 2003-10-29
  • 打赏
  • 举报
回复
错。。。。
偶笔误了。。
ihihonline 2003-10-29
  • 打赏
  • 举报
回复

但TControlFactory的功能是创建其他实例(FControlObj),它所保存的唯一变量(FControlObj)只是一个实例的引用,不需要分配多少内存。所以可以不用考虑内存回收问题。
/////////
这句话并没有正真的解决上边的疑惑,类工厂本身也只是一个类,用来创建其它实例,但是,以这这个例子的方法进行下去的话,感觉有些事倍功半,而且本身就已经有违于模式理念;


DelphiWizard 2003-10-29
  • 打赏
  • 举报
回复
我认为内存的泄漏和回收问题,无论提问的还是回答都很明白,无需旁人指点。何况作者在这本书中有专门的章节不厌其烦地讨论了这个问题。
如果不是孤立地看这段代码,而是联系书中这段上下文去理解的话,不难发现作者此处的良苦用心。其实,示例程序3-9就是一个无可挑剔的程序,很规范的工厂方法模式。远比chechy的解决方法好。可是作者又为何要冒内存泄漏的风险画蛇添足呢?(作者肯定知道会有内存泄漏。这一点我不怀疑)。我想无非是欲通过打破常规的思路演示修改构造函数的奇特效果。这一点在书中示例程序3-10之前就有详细的交代和铺垫。
当然,删掉这段代码对作者来说是很容易的。不过,至少我自己认为通过这段代码我理解了构造函数和self的作用,明白了构造函数隐式返回了self(这就是为什么叫构造函数,而不是叫构造方法)。以前,我编程很少敢在构造函数中作手脚,都是保守的写法TXXX.create;现在至少我会乐于做这方面的尝试。
newdream 2003-10-28
  • 打赏
  • 举报
回复
给读者的回复:
----------------------------------------------
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
mycsdnid 2003-10-28
  • 打赏
  • 举报
回复
高手过招,我搬个凳子看看可以吧!
xzgyb 2003-10-28
  • 打赏
  • 举报
回复
是啊,我也感觉没什么绝妙的
他的第一个例子是用的类方法
这是第二个例子
书上的原话:
'更绝妙的是通过一条转型赋值语句,将动态创建的控件对象FContorlObj向上转型为
TControlFactory类型,并赋值给TControlFactory自身,由TControlFactory来传递,
这就使得TControlFactory有了七十二变的本事';
我看的晕晕乎乎的
lxpbuaa 2003-10-28
  • 打赏
  • 举报
回复
不明白啊。首先我觉得这没什么“绝妙”的,不就是使用类引用吗?再说了,类工厂也不应该这样来用吧,怎么用TControlFactory本身的构造函数来创建需要的实例呢?因为类工厂本身也应该是一个对象,它这样子一弄,类工厂本身就没有了。为什么不使用类方法呢?这样也无需创建类工厂实例就可以制造对象。

————————————————————————————————————
宠辱不惊,看庭前花开花落,去留无意;毁誉由人,望天上云卷云舒,聚散任风。
————————————————————————————————————
Linux2001 2003-10-28
  • 打赏
  • 举报
回复
幸好我没有买啊!
FrameSniper 2003-10-28
  • 打赏
  • 举报
回复
书买了还没看,直接问刘艺人家也很少理我(哭....)

8过,现在写书的这些人我感觉水平也是高低层次不齐,而且水平高的也经常会在书中发生错误!比如乔林的《参透Delphi/Kylix》里面就有一个大错误!
chechy 2003-10-28
  • 打赏
  • 举报
回复
不仅丢了,而且找不回来。不懂,为什么要去修改Self,这样有什么好处呢?Delphi又不是Java或者C#,可以自动回收内存,没有Owner的话,根本无法自动管理内存。
刘艺的口碑并不好,以前写的Midas的书就很烂,不客气的说是误人子弟。
saien 2003-10-28
  • 打赏
  • 举报
回复
Self := TControlFactory(FControlObj);//完全正确。
tanqth 2003-10-28
  • 打赏
  • 举报
回复
看不懂!
没时间看
sixgj 2003-10-28
  • 打赏
  • 举报
回复
看不懂!

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧