很多朋友看了上次我寫的“創建良好設計的代碼(基於Delphi/VCL)”後,對我說感覺上可以接受其中的觀點,但似乎說得太簡單,不夠具體;也有的朋友對其中的一個小例子有些異議。因此便有了此文。
上次,我舉的例子是這樣的:假設要從某處獲得一個字符串列表,然後顯示於 TListBox 中,我所推崇的代碼是:
ObjectXXX := TObjectXXX.Create;
ListBox1.Items := ObjectXXX.GetStringList;
ObjectXXX.Free;
的確,我承認,單純從這三行代碼來看,似乎有了“濫用對象”之嫌。也許是例子過於簡單,給人的感覺是TObjectXXX只有GetStringList這一個public成員函數,如果真的這樣的話,那可真是“濫用對象”了。類是對對象的抽象,而對象是由狀態和操作(也就是數據和對數據的操作)的集合組成。因此,沒有狀態的對象不是對象!沒有私有數據成員的類的設計是失敗的設計(那不是類,而是接口了)。
好,下面我就舉一個詳細的例子來說明,如何將界面代碼和功能代碼分離。
假設我要做一個簡單的個人通訊錄管理軟件,很顯然,整個軟件分為兩部分:一部分是面象用戶的,也就是所謂界面部分,我可以提供四個按鈕(分別為“添加”、“刪除”、“修改”、“查找”)和一個編輯框(顯示通訊錄信息和接受用戶輸入)用於和用戶交互;另一部分是功能化的,也就是軟件內部的對於通訊錄的存取操作。
於是,有了一個TAddrBook類,它是對功能化部分的抽象。
TAddrBook = class
private
//一些私有成員
public
constructor Create;
destructor Destroy;override;
GetCount: Integer;
FindRecord(strString): Integer;
GetRecord(nIndex:Integer): String;
SetRecord(nIndex:integer; strRec:String): Boolean;
AddRecord(strRec:String): Boolean;
DelRecord(nIndex): Boolean;
//其它共有成員函數
end;
私有成員之所以無法確定,主要是取決於這個類的實現。
如此,可以將對通訊錄的存取操作的邏輯封裝。而界面部分的代碼不會涉及到這些存取邏輯。界面部分代碼如下:
var
Form1: TForm1;
AddrBook: TAddrBook;
nCurRec: Integer;
implementation
procedure TForm1.FormCreate(Sender: TObject);
begin
AddrBook := TAddrBook.Create;
nCurRec := AddrBook.GetCount;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
AddrBook.Free;
end;
//添加按鈕
procedure TForm1.Button1Click(Sender: TObject);
begin
if not AddrBook.AddRecord(memo1.Text) then
ShowMessage("error");
end;
//刪除按鈕
procedure TForm1.Button2Click(Sender: TObject);
begin
if not AddrBook.DelRecord(nCurRec) then
ShowMessage("error");
end;
//修改按鈕
procedure TForm1.Button3Click(Sender: TObject);
begin
if not AddrBook.SetRecord(nCurRec, memo1.Text) then
ShowMessage("error");
end;
//查找按鈕
procedure TForm1.Button4Click(Sender: TObject);
begin
memo1.Text := AddrBook.GetRecord(AddrBook.FindRecord(memo1.Text));
end;
以上界面部分的代碼,不涉及任何存取邏輯,每個模塊的代碼簡單,易懂,便於維護。而實際上,該通訊錄是使用數據庫保存還是用文本文件來保存,界面代碼都不知道;使用數據庫的話,是通過ODBC還是ADO還是BDE訪問數據庫,界面代碼也不知道。實際上,這些存取邏輯的東西取決於TAddrBook類的實現,TAddrBook類的實現可以單獨的放在一個.pas文件中,對TAddrBook類的實現的任何更改,都不會影響界面部分。維護代碼的時候,將更改局限於某一個模塊中的做法是非常明智的。