[16:37:23] JingYu : 有空吗?
[16:37:37] Aimingoo:
[16:37:43] JingYu : 想讨论个问题
[16:38:03] Aimingoo: 可以呀。
[16:38:13] JingYu : vcl 里头窗体上的控件和关联的事件都是 published 的,你觉得这样处理的理由是什么?
[16:38:20] JingYu : 除了RTTI的需要。
[16:38:55] Aimingoo: 只是因为RTTI的需要。
[16:38:58] JingYu : unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics,
Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
private
btn1: TButton;
public
constructor Create(AOwner : TComponent);override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
constructor TForm1.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
btn1 := FindComponent('btn1') as TButton;
end;
initialization
RegisterClass(TButton);
end.
[16:39:06] Aimingoo: 我记得在什么资料里看到过。
[16:39:37] Aimingoo: 而且,如果需要在属性编辑器里处理,也是需要先声明成published的。
[16:39:51] JingYu :
有人给出这样的代码,认为“就我个人的看法,不管是否封装对窗体访问或是否使用interface等手段,设计器生成的这些定
义严重污染了类的接口。”
[16:40:10] JingYu : 对,RTTI的需要我们都知道。
[16:40:19] JingYu : 我只是想从面向对象和设计的角度来看
[16:43:38] Aimingoo: 他这段代码,与他的观点,有什么关系吗?我看不出来~~
[16:44:04] JingYu : 这段代码是把published的控件转化成private的实现
[16:44:40] JingYu : 这个btn1估计还在窗体上,就是从申明中去掉了。
[16:46:29] JingYu : 他认为窗体上的控件不应该被其它类访问到。
[16:46:58] JingYu :
http://bbs.cnpack.org/viewthread.php?tid=412
[16:48:28] Aimingoo: 是的。他这样声明,的确可以被form1访问到,但是,界面设计器可能不能处理了。
[16:48:43] JingYu : 可以处理,我刚才试了下。
[16:48:56] JingYu : 把btn1移到private下,设计器还可以访问
[16:48:57] Aimingoo: OH.
[16:49:03] JingYu : 编译也能正常执行
[16:49:03] Aimingoo: 哈哈。
[16:49:35] Aimingoo: 因为我曾经把这个部分的代码做成.inc,结果是不能处理的,后来,我就只好做成了frame。哈哈。
[16:50:02] JingYu : 不过必须要 RegisterClass(TButton);
才能正确执行
[16:50:58] Aimingoo:
在窗体中的界面元素,例如button,其实应该是可以被其它单元或外部的代码访问的。因为无论如何,代码可以通过compo
nents来访问到指定的界面元素。
[16:51:13] JingYu : 对,这也是我的想法。
[16:51:37] Aimingoo: 这种隐藏,是效率上的失败。——除了,interface上看起来让人心情好一些。
[16:52:20] JingYu : 估计vcl在从流中创建窗体时,也是用RTTI的方法来设置published的控件名的。
[16:52:51] JingYu : 抛开效率,这种方法还有其它问题吗?
[16:52:53] Aimingoo:
然而,你想,你放在UI上,当然是用于被处理、被控制的。要不然,你就直接做create得了。——UI上的控件被放dfm里
,在初始form时可以被创建。而放在privited节里不能。
[16:53:09] Aimingoo: 这也是必须要RegisterClass()才能用的原因呢。
[16:53:31] JingYu : 好象不太对吧。
[16:53:33] Aimingoo: 所以,从这里来看。也是Delphi窗体自动构建机制的需要。
[16:54:01] JingYu :
必须要RegisterClass的原因是因为只有注册了,流化的窗体创建时才能用FindClass根据名称找到类的引用吧
[16:54:08] Aimingoo: ——哈哈~~是这样的罢。
[16:54:32] JingYu : 如果直接用 TForm1.Create,也应该是可以正常工作的。
[16:55:01] JingYu : vcl在TCustomForm的构建器里头会自动从RCDATA资源里头读流化的窗体数据。
[16:55:09] Aimingoo: En...这个你需要测试。
[16:55:21] Aimingoo: 我的印象中是这样。
[16:55:34] JingYu : 这也限制了用户直接从TCustomForm派生子类
[16:57:06] JingYu : 从设计的角度考虑,前面的代码是否有问题呢?
[16:58:33] Aimingoo:
不不。从设计的角度上来看,UI层是尽可能公开,而不是隐蔽。公开的组件信息有利于代码的编写,而且。EN...
[16:59:21] Aimingoo: 我想想。域占有的内存空间是一致的,无论它是public还是privated....
[16:59:56] JingYu : 嗯,如果在published里头,窗体从流中加载时,会根据RTTI给属性赋值。
[17:00:05] JingYu : private的话,得自己赋值。
[17:00:08] Aimingoo: 也就是说,他做了一件不必要做的事。
[17:00:34] JingYu : 他的出发点是信息隐藏。
[17:01:55] Aimingoo: En.
[17:02:29] Aimingoo: 没必要呀。因为在这一个层面上的设计,基本的思路就是公开。而不是背其道而行之。
[17:06:34] JingYu : 嗯。
[17:07:14] JingYu : 窗体只是界面表现层的东西,每个窗体都应该是相对独立的。
[17:08:23] Aimingoo: En...
[17:09:24] Aimingoo:
还有,界面层的hwnd都是可以通过api来遍历的,这是win32的问题。但这表明,对于这一层的隐藏,OS提供了机制来突
码。但显然这是不方便的。
[17:10:49] Aimingoo:
也没有必要做得如此复杂。在这一层面上,Delphi可能更偏向于开放的设计。而不是隐藏。——如果你有印象,你应该知道要在
shell的dialog中加一个button,是非常困难的。这种API一层的隐藏是以易用性为代码的。
[17:11:17] JingYu : 对。
[17:11:59] Aimingoo:
如果从设计的角度上来看,这个dark_moon的思路,可能也是以易用性为代价,来换取接口的“纯净”,或者“漂亮”。这当
然是不值得的。
[17:13:14] JingYu : 从另一面考虑,即使published上什么也不加,窗体从 TForm
继承来的属性和方法在一个接口封装的系统中也是不希望全部开放给其它用户的。
[17:13:34] Aimingoo:
[17:14:33] JingYu : 既然VCL本身的设计是以这种机制来处理窗体的,硬要去封装,有些得不偿失了。
[17:14:41] Aimingoo: 是呀。
[17:15:41] Aimingoo: 是否要封装、封闭,取决于环境和设计目标,而不是反过来,以封装与封闭为设计目标。
[17:15:43] JingYu : 我记得有些delphi编码规范上面是要把自动声明的窗体的变量去掉,改成手工创建的。
[17:15:47] Aimingoo: 对不对~
[17:16:01] JingYu : 对。
[17:16:29] Aimingoo: JingYu 说:
我记得有些delphi编码规范上面是要把自动声明的窗体的变量去掉,改成手工创建的。
---------
这个倒是正常的。我也比较习惯这样做。因为~~这会加快初始化的速度。
[17:16:57] JingYu : 呵呵,我指不不是AutoCreate,是指把 var Form1: TForm1 这个变量删除。
[17:17:14] JingYu : 以防止其它用户通过这种全局变量来访问窗体。
[17:17:43] Aimingoo: 是呀。
[17:17:43] JingYu : 好象《D5开发人员指南里头》也有提到。
[17:17:58] Aimingoo: 去掉这个变量,就不会自创建乐。哈哈~~
[17:18:32] JingYu : 如果是多人开发的话,模块的接口应该单独设计,而不应该依赖于窗体类的接口定义吧。
[17:18:33] Aimingoo: Options里的选项是对应于这个变量的。
[17:18:54] JingYu : Options里的选项还针对.dpr文件里的初始化代码呀
[17:19:36] JingYu : 如果只删除变量,不从设置或.dpr里删除,会编译报错的,呵呵。
[17:19:39] Aimingoo: OH...是的。我当然都是两个都去掉。如果你把var
form1的声明去掉了,哈,不改.dpr里的代码,就编译不过~~哈哈。
[17:19:43] Aimingoo: 哈哈哈~~
[17:19:46] JingYu :
[17:19:54] Aimingoo: 这两句怎么打出来都一样啊。
[17:19:57] Aimingoo: 哈哈哈。
[17:20:00] JingYu : 我的设置里头默认就是不创建,呵呵。
[17:21:38] JingYu : 所以我主张,如果要考虑类和模块的接口封装,应该用类或接口来封装窗体,而不是去隐藏窗体上的控件。
[17:22:11] Aimingoo: 是的。
[17:22:41] Aimingoo: 要进一步的封装窗体。我建议用Frame. 这是我常用的简化代码的方法。
[17:23:18] JingYu : 不过用Frame的话,封装的只是窗体中的一部分界面和功能,而不是接口吧。
[17:23:30] JingYu : Form1.Frame1.Button1还是可以访问的。
[17:25:18] JingYu : 聊天记录我整理下,帖上去,可以吧?
[17:26:24] Aimingoo: