B
Bahl
Unregistered / Unconfirmed
GUEST, unregistred user!
[h2] RAD,怀璧其罪[/h2]
Delphi的一个独一无二的特点就是它既是一个可视化的开发工具,同时也是一个面向对象的编程环境。事实上,各种类型的组件(不论其是否可视化)都是以类的方式实现的。每当
你定义一个新窗体时,你就创建了一个新类。屏幕与窗体上的每个组件都是组件类或窗体类
的一个实例。Delphi的组件模型首次使可视化编程与面向对象编程之间的天堑变成了通途。
JavaBean从这种模型中获益良多,而微软的可视化工具则没有一个能达到这种境界。
在Delphi中,类与组件之间并没有显著的区别。从技术角度来讲,组件是从TComponent类
派生出来的类的对象,TComponent类处于VCL层次结构中的最顶端。正像你所知道的那样,
从TComponent类派生要求将你的类或组件安装到组件面板上并在设计期操作它。在运行期,
所有的对象(不论是否组件)都一视同仁。
[h3]影响与效果[/h3]
一个组件就是一个对象,这有什么实际意义呢?它意味着你能使用代码做你在开发环境中所能做的任何事。你不仅可以在运行期使用Object Pascal代码来动态地建立组件,将它们放
置到窗体上,还可以钩挂你编写的事件处理器。换句话说,你可以使用两种完全不同的方法
将一个按钮放置到窗体上。你既可以通过在Delphi IDE中拖动一个按钮图标到窗体上来将一
个按钮放置到窗体上,也可以通过写几行代码来做同样的事情。
可视化的方法既简单又快捷,不过写代码的方法灵活性更强,威力更大。只要你用Delphi
写程序,就不可能用不着对象。不过对象使用起来要比你想象的容易得多。问题在于为了使
编码变得更容易,Delphi的可视化工具支持某些不好的编程习惯。事实上,Delphi有许多默
认行为,它们对初学者与快速开发应用程序有益,但对复杂的范例有害,因为它们违反了面
向对象编程的一个关键原则:封装。
[h3]便利但是有害[/h3]
系统通常会自动为每个类声明一个全局变量,这方便了编程,但却容易产生混淆。Delphi新手常常会将Form1与TForm1当作一回事。他们在类方法的代码中引用TForm1这个特殊的对象
,这就不能生成窗体的多个拷贝。更糟糕的是,他们会引用其他的窗体类的某个特殊的全局对
象。我知道这样做能节省编码时间,但是这是一种不好的习惯,它增加了耦合性。
在一个窗体中公布某个组件的域也会发生问题。因为它同样地增加了耦合性。尽管与窗体相
联系的域与与组件相联系的域是有关系的,但它们仍然是两码事。将它们混同起来(这是一种
很常见的错误)会产生很不好的效果。我的原则是绝不在一个窗体中引用另一个窗体的组件。
那么怎样才能做到这点呢?你可以为窗体编写一些与以窗体为宿主的组件联系的属性与方法。
这样就能封装组件,否则你的用户接口每改变一次都会导致一场灾难!
这里有一个例子。假设你的主窗体上有一个用来显示信息的状态栏。你可以在别的窗体中通
过下面这行代码来显示信息:
Form1.StatusBar1.Panels[2].Text := 'my message';
如果你改变了用户界面,想让状态栏的另一个面板显示信息时你该怎么办?如果你用别的
组件代替了状态栏或是想记录信息时你又该怎么办?你必须得改写相关的代码,而它也许会
在程序的所有单元中出现,足足有378处之多!想听听我的建议?给窗体加上一个信息属性,
当信息改变时在状态栏中显示信息。你可以参考一下HideComp这个例子。
我在这里所提到的问题只不过是冰山的一角,还有许多面向对象编程的技术问题没有在这里
探讨。如果你有兴趣,可以参考一下Delphi Magazine,我在里面的一篇文章中列举了有关面
向对象编程规则的一份详细的清单。除了上面所举的那个例子以外,我还在那篇文章中探讨了
其他两种技术:可视化窗体继承与通过编写通用组件来共享代码。
除了应该按照面向对象的原则来使用组件以外,应用程序的整个结构也应该是面向对象的。
这意味着要在按照面向对象的原则来管理,操作数据与研究程序逻辑的实现这两方面下更大
的功夫。我正在研究这些问题。我将在不久后开辟一个新专栏里告诉你我的发现。如果你现
在就对它感兴趣,Scott Ambler的网站是一个很不错的起点。