进一步将界面代码和功能代码分离(基于DELPHI/VCL)之一
-----如何将界面代码和功能代码分离(基于Delphi/VCL)一文之补充建议

读过Nicrosoft(奈软) 朋友的‘如何将界面代码和功能代码分离’一个,
很是佩服, 仔细读过之后, 我想补充我对在DELPHI上实现界面与功能代码,这方面的体会。

还是拿Nicrosoft的个人通讯录管理作为例子还说吧,
可参见:

Nicrosoft朋友定义了一个TAddrBook的类来封装了一个地址簿存取操作的逻辑,
对外提供了
    FindRecord,    AddRecord, DelRecord。。。
等等必需的公共接口,
然后在一个TFORM作为地址簿的显示界面,仅使用这些公共接口去访问TAddrBook实例。
不涉及任何存取逻辑,每个模块的代码简单,易懂,便于维护。

Nicrosoft的TAddrBook类是没有指定父类, 也就是说继承自TObject,因为我们
谈的DELPHI, 为了充分利用它的可视化环境(当然,不仅仅因为这点),
我建议将其继承于TDataModule, 简单地说,创建一个数据模块,将其命名为TAddrBook.

仔细想想, 可能会发现仅仅这样,还有些地方不尽如人意,
在这个地址簿运行时,产生了一个TForm1类实例(暂称其Form1)
和一个TAddrBook类实例(暂称其AddrBook),它们之间通讯
是单向的,也就是说Form1知道AddrBook,而AddrBook不知道Form1,
Form1必需知道AddrBook是显而易见的,而AddrBook需要知道Form1吗?
这个嘛。。。。有点不大好说。。。至少有一个地方可能会需要的吧,
就是AddrBook记录改变的时候,得叫Form一声“喂,FORM,我变了”,
不过仅仅这样看来,它还是似乎可有可无,Form1可以主动去查询AddrBook的状态。

再多想想, 如果另建了一个实例TForm2类呢? 或者是一个TForm1的多个类实例呢?
这样有两个以上的FORM都要去显示AddrBook,那情况会是怎么样?
说得实际些,比如说FORM1是个LISTVIEW显示,
而FORM2是个DETAIL显示与编辑, 在FORM1中选了另一个人,FORM2显然必须得相应的
变化,直接由FORM1通知FORM2吗? 这不是个好主意。
如果这样,独立自在的FORM,本来只需要知道AddrBook,还得知道其它的FORM,FORM的数量越多,
越有扯不清的关系。增加删除一个FORM还得看其它的FORM的脸色行事,NO,这样不爽!
那好吧, 就决定让AddrBook知道有哪些FORM在用它吧,然后在必要的时候通知大家自己状态变了,
再来读自己一次。
具体实现的方法很多, 我是比较喜欢用TList,
首先,TAddrBook的私有成员中加一个
private
  FViewerList:TList;//用来保存使用TAddrBookr的FORM
...
然后,加上这几个方法。。
public
...
    procedure AddViewer(form:TForm);    AddrBook的FORM登个记
    procedure RemoveViewer(form:TForm); 销这个FORM的登记
    procedure TellAllViewer();                    知所有登记过的FORM

...

procedure TAddrBook.AddViewer(form: TForm);
begin
    FViewerList.Add(form);
end;
procedure Tfrm_Navigate.RemoveViewer(form: TForm);
begin
    FViewerList.Remove(form);
end;
下面是通知所有使用TAddrBook的FORM, 有很多种方法的,
我这儿采用的是发送消息的方法,
已经自定义了一个消息
。。。
MY_ADDRBOOK_MSG =WM_USER+100;
。。。

procedure TAddrBook.TellAllViewer;//告诉所有的FORM‘喂,都该起来做事了’
var
   i:integer;
begin
    for i := 0 to FViewerList.Count-1 do
    begin
        postMessage(
            TForm(  FViewerList.Items[i]  ).Handle,
            MY_ADDRBOOK_MSG,
                 0 , 儿两个参数可以用来区分你发出通知的种类,
                 0    主张用它们来直接传数据回FORM,
                       是在通知让FORM来取数据
                 );

    end;
end;

而在TFORM1中,加入消息处理方法。

  TForm1 = class(TForm)
...
public
      procedure AddrBookNotify(var Message: TMessage); message MY_ADDRBOOK_MSG;
...

procedure TForm1.AddrBookNotify(var Message: TMessage);
begin
    
    这里面重新读出AddrBook的信息,
    然, 视你消息的分类,还可以处理得更细一些

end;

AddrBook中的方法进行改变数据状态的行为后,需要FORM相应改变显示或其它类似的操作时,
就调用TellAllViewer方法。


罗里罗嗦,终于说得差不多了, 真累,
如果知道设计模式的朋友, 一眼就可以知道这是观察者模式, 也就是VC应用程序框架中
所采用的Doc /View 模式, 就一两句话可以搞定。

之所以在标题上加了一个‘之一’, 是因为还有很多值得进一步思考的东西,
如果有必要, 我,或者其它有兴趣的朋友, 可以继续探讨,加上之二,之三。

                                        halfdream(哈欠)
                                                                              2000。7。15