目錄:
- 前言
- 源程序書寫規范
- 通用源代碼書寫規范
- Object Pascal語句書寫規范與用法
- 命名規范
- 過程(PRocedure)與函數(Function)
- 變量(Variable)
- 類型(Type)
- 一般類型
- 構造類型
- 類類型(Class)
- 字段
- 方法
- 屬性
- 元件類型
- 窗體與對話框類型
- 數據模塊類型
- 文件
- 項目文件(.dpr)
- 窗體文件(.dfm)
- 數據模塊文件
- 遠程數據模塊文件
- 單元文件(.pas)
- 普通單元
- 窗體單元
- 通用單元
- 元件單元
- 包文件(.dpk)
- 源程序文檔注釋規范
- 注釋文檔的一般規范
- 單元文件注釋文檔格式
- 函數(屬性)的注釋文檔格式
- Delphi代碼自動格式化工具
- 代碼標準文檔更新
- 附錄:參考文獻
本文檔主要是為Delphi開發人員提供一個源代碼書寫標準,以及程序和文件的命名標準,使他們在編程時有一致格式可遵循。這樣,每個編程人員編寫的代碼能夠被其他人理解。
本文檔不包含用戶界面標準。用戶界面標準是獨立于其他標準的,并且同樣是重要的。
1). 縮進
縮進就是每級間有兩個空格。不要在源代碼中放置制表符。這是因為,制表符的寬度隨著不同的設置和代碼管理實用程序(打印、文檔及版本控制等)而不同。
通過使用Tools|Environment 菜單,在Environment Options 對話框的General頁上,不要選中Use Tab Character 和Optional Fill 復選框,這樣,制表符就不會被保存。
2). 邊距
邊距設置為80個字符。源代碼一般不會因寫一個單詞而超過邊距,但本規則比較靈活。只要可能,長度超過一行的語句應當用逗號或運算符換行。換行后,應縮進兩個字符。
3). begin...end 語句
begin 語句必須單獨占一行。例如,下面第一行是錯誤的,而第二行正確:
for i:=0 to 10 do begin // 錯, begin 與f o r 在同一行
for i:=0 to 10 do // 對, begin 在另外一行中
begin
本規則的一個特殊情況是,當begin 為else 語句的一部分時,例如:
if some statement = then
begin
. . .
end
else begin
Some Other Statement;
end;
注意:end 語句總單獨一行。當begin 不為else 語句的一部分時,相應的end 語句與begin 語句的縮進量相同。
4).注釋
我們通常使用“{...}”類型的塊注釋,以前的“(*...*)”類型的塊注釋用于臨時注釋掉暫不使用的代碼,從Delphi 2開始支持“//”行注釋,如果決定不在支持Delphi 2.0以下的版本,可以使用“//”注釋。
1). 括號
在左括號與下一字符之間沒有空格。同樣,右括號與前一字符也沒有空格。下面的例子演示了正確與不正確的空格。
CallProc( Aparameter ); // 錯!
CallProc(Aparameter); // 正確!
不要在語句中包含多余的括號。在源代碼中,括號只有在確實需要時才使用。下面的例子演示了正確與不正確用法:
if (I=42) then // 錯,括號是多余的
if (I=42) or (J=42) then // 正確,必須使用括號
2). 保留字和關鍵字
Object Pascal 語言的保留字和關鍵字總是完全的小寫。下面是Delphi 5保留字列表:
and | array | as | asm |
begin | case | class | const |
constructor | destructor | dispinterface | div |
do | downto | else | end |
except | exports | file | finalization |
finally | for | function | goto |
if | implementation | in | inherited |
initialization | inline | interface | is |
label | library | mod | nil |
not | object | of | or |
out | packed | procedure | program |
property | raise | record | repeat |
resourcestring | set | shl | shr |
string | then | threadvar | to |
try | type | unit | until |
uses | var | while | with |
xor | private | protected | public |
published | automated | | |
3). 過程和函數
(1). 格式
過程名應當以大寫字母開始,且大小寫交錯以增加可讀性。下面是一個不正確的寫法:
procedure thisisapoorlyformattedroutinename;
改成這樣寫就對了:
procedure ThisIsMuchMoreReadableRoutineName;
(2). 形參
(1) 格式
只要可能,同一類型的形參應當歸并在一起:
procedure Foo(Param1,Param2,Param3:Imteger;Param4:string);
(2) 參數順序
形參的順序主要要考慮寄存器調用規則。最常用的參數應當作為第一個參數,按使用頻率依次從左到右排。輸入參數位于輸出參數之前。范圍大的參數應當放在范圍小的參數之前。例如:
SomeProc(aPlanet, aContinent, aCountry, aState, aCity).
有些則例外。例如,在事件處理過程中,TObject 類型的Sender 參數往往是第一個要傳遞的參數。
(3) 常量參數
要使記錄、數組、短字符串或接口類型的參數不能被過程修改,就應當把形參標以Const 。這樣,編譯器將以最有效的方式生成代碼,保證傳遞的參數不可變。
如果其他類型的參數希望不被過程所修改,也可以標上Const 。盡管這對效率沒有影響,但這給過程的調用者帶來了更多的信息。
4). 變量
(1). 局部變量
局部變量用于過程內部,果需要的話,應當在過程的入口處立即初始化變量。局部的AnsiString 類型的變量自動被初始化為空字符串,局部的接口和dispinterface類型的變量自動被初始化為nil,局部的Variant和OleVariant類型的變量自動被初始化為Unassigned。
(2). 全局變量
一般不鼓勵使用全局變量。不過,有時候需要用到。即使如此,也應當把全局變量限制在需要的環境中。例如,一個全局變量可能只在單元的實現部分是全局的。
全局數據如果將由許多單元使用,就應移動到一個公用單元里被所有對象使用。全局數據可在聲明時直接初始化為一個值。注意,所有全局變量自動進行零初始化,因此,不要將全局變量初始化為諸如0 、nil、或Unassigned等空值。零初始化的全局變量在.EXE文件中不占空間。零初始化的數據保存在虛擬的數據段中,而虛擬數據段只在應用程序啟動時才分配內存。非零初始化的全局數據則在.EXE文件中占空間。
5). 類型
(1). 大小寫規則
類型標識符是保留字,應當全部小寫。Win32 API 類型常常全部大寫,并且遵循諸如Windows.pas或其他API單元中關于特定類型名的規則。對于其他變量名,第一個字母應大寫,其他字母則大小寫交錯。下面是一些例子:
var
MyString: string; // 保留字
WindowsHandle: HWND; // Win32 API 類型
I: Integer; //在System單元中引入的類型標識
(2). 浮點型
不鼓勵使用Real類型,因為它只是為了與老的Pascal代碼兼容而保留的。通常情況下,對于浮點數應當使用Double。Double可被處理器優化,是IEEE定義的標準的數據格式。當需要比Double提供的范圍更大時,可以使用Extend。Extend是intel專用的類型,
java不支持。當浮點變量的物理字節數很重要時(可能使用其他語言編寫DLL),則應當使用Single。
(3).Variant和OleVariant
一般不建議使用Variant和OleVariant。但是,當數據類型只有在運行期才知道時(常常是在COM和
數據庫應用的程序中),這兩個類型對編程就有必要。當進行諸如自動化ActiveX控件的COM編程時,應當使用OleVariant;而對于非COM編程,則應當使用Variant。這是因為,Variant能夠有效地保存Delphi的原生字符串,而OleVariant則將所有字符串轉換為OLE字符串(即WideChar字符串),且沒有引用計數功能。
6). 語句
(1). If 語句
在if/then/else語句中,最有可能執行的情況應放在then子句中,不太可能的情況放在else子句中。為了避免出現許多if語句,可以使用case語句代替。如果多于5級,不要使用if語句。請改用更清楚的方法。不要在if語句中使用多余的括號。
如果在if語句中有多個條件要測試,應按照計算的復雜程度從右向左排。這樣,可以使代碼充分利用編譯器的短路估算邏輯。例如,如果Condition1比Condition2快,Condition2比Condition3快,則if語句一般應這樣構造:
if Condition1 and Condition2 and Condition3 then
如果Condition3為False的機會很大,利用短路估算邏輯,我們也可以將Condition3放在最前面:
if Condition3 and Condition1 and Condition2 then
(2). case 語句
(1) 概述
case語句中每種情況的常量應當按數字或字母的順序排列。每種情況的動作語句應當簡短且通常不超過4 - 5 行代碼。如果動作太復雜,應將代碼單獨放在一個過程或函數中。Case語句的else子句只用于默認情況或錯誤檢測。
(2) 格式
case語句遵循一般的縮進和命名規則。
(3). while 語句
建議不要使用Exit過程來退出while循環。如果需要的話,應當使用循環條件退出循環。所有對while循環進行初始化的代碼應當位于while入口前,且不要被無關的語句隔開。任何業務的輔助工作都應在循環后立即進行。
(4). for 語句
如果循環次數是確定的,應當用for語句代替while語句。
(5). repeat 語句
repeat語句類似于while循環,且遵循同樣的規則。
(6). with 語句
(1) 概述
with語句應小心使用。要避免過度使用with語句,尤其是在with語句中使用多個對象或記錄。例如:
with Record1,Record2 do
這些情況很容易迷惑編程人員,且導致調試困難。
(2) 格式
with語句也遵循本章關于命名和縮進的規則。
7). 結構化異常處理
(1). 概述
異常處理主要用于糾正錯誤和保護資源。這意味著,凡是分配資源的地方,都必須使用try...finally來保證資源得到釋放。不過,如果是在單元的初始/結束部分或者對象的構造器/析構器中來分配/釋放資源則例外。
(2). try...finally的用法
在可能的情況下,每個資源分配應當與try...finally結構匹配,例如,下面代碼可能導致錯誤:
SomeClass1 := TSomeClass.Create;
SomeClass2 := TSomeClass.Create;
try
{ do some code }
finally
SomeClass1.Free;
SomeClass2.Free;
end;
上述資源分配的一個安全方案是:
SomeClass1 := TSomeClass.Create;
try
SomeClass2 := TSomeClass.Create;
try
{ do some code }
finally
SomeClass2.Free;
end;
finally
SomeClass1.Free;
end;
但有時如果有許多類都需要同時創建,上述方案就顯得非常累贅。這時候,我建議使用下述的一個安全方案:
SomeClass1 := nil;
SomeClass2 := nil;
SomeClass1 := TSomeClass.Create;
SomeClass2 := TSomeClass.Create;
try
{ do some code }
finally
FreeAndNil(SomeClass1);
FreeAndNil(SomeClass2);
end;
(3). try...except的用法
如果你希望在發生異常時執行一些任務,可以使用
try...
except。通常,沒有必要為了簡單地顯示一個錯誤信息而使用
try...
except,因為
application對象能夠自動根據上下文做到這一點。如果要在子句中激活默認的異常處理,可以再次觸發異常。
(4). try...except...else的用法
不鼓勵使用帶else子句的try...except,因為這將阻塞所有的異常,包括你沒有準備處理的異常。
1).命名
過程與函數名應當有意義。進行一個動作的過程最好在名稱前加上表示動作的動詞為前綴。例如:
procedure FormatHardDrive;
設置輸入參數值的過程名應當以Set 為其前綴,例如:
procedure SetUserName;
獲取數值的過程名應當以Get 為其前綴,例如:
function GetUserName:string;
2).形參
所有形參的名稱都應當表達出它的用途。如果合適的話,形參的名稱最好以字母a 為前綴,例如:
procedure SomeProc(aUserName:string; aUserAge:integer);
當參數名與類的特性或字段同名時,前綴a 就有必要了。
3).命名沖突
當兩個單元中含有相同名稱的過程時,如果調用該過程,實際被調用的是Uses 子句中較后出現的那個單元中的過程。為避免這種情況,可在方法名前加想要的單元名,例如:
SysUtils.FindClose(SR);
或Windows.FindClose(Handle);
變量的名稱應當能夠表達出它的用途。循環控制變量常常為單個字母,諸如I 、J 或K 。也可以使用更有意義的名稱,例如UserIndex。布爾變量名必須能清楚表示出True 和False 值的意義。
1). 局部變量
局部變量遵循其他變量的命名規則。
2). 全局變量
全局變量以大寫字母“G”打頭,并遵循其他變量的命名規則。
1). 枚舉型
枚舉類型名必須代表枚舉的用途。名稱前要加T字符作為前綴,表示這是個數據類型。枚舉類型的標識符列表的前綴應包含2 - 3 個小寫字符,來彼此關聯。例如:
TSongType=(stRock, stClassical, stCountry, stAlternative, stHeavyMetal, stRB);
枚舉類型的變量實例的名稱與類型相同,但沒有前綴T ,也可以給變量一個更加特殊名稱,諸如:FavoriteSongTypel、FavoriteSongType2等等。
1). 數組類型
數組類型名應表達出該數組的用途。類型名必須加字母“T”為前綴。如果要聲明一個指向數組類型的指針,則必須加字母P 為前綴,且聲明在類型聲明之前。例如:
type
PCycleArray = ^TCycleArray;
TCycleArray=array[1..100] of integer;
實際上,數組類型的變量實例與類型名稱相同,但沒有“T”前綴。
2). 記錄類型
記錄類型名應表達出記錄的用途。類型名必須加字母T為前綴。如果要聲明一個指向記錄類型的指計,則必須加字母P為前綴,且其聲明在類型聲明之前。例如:
type
PEmployee = ^TEmployee;
TEmployee = record
EmployeeName: string;
EmployeeRate: Double;
end;
1). 命名與格式
類的名稱應當表達出類的用途。一般的類名前要加字母“T”,如果是接口類那么類名前要加“I”,錯誤異常類的類名前要加“E”,而類引用類型(Class-reference type)則要在類名后加“Class”,抽象類一般是在類名前還要加“Custom”。例如:
type TCustomC
ipher =
class(TObject);
TCipher =
class(TCustomCipher);
ICipher =
interface;
TCipherClass =
class of TCustomer
ECipherException = class(Exception);
類的實例名稱通常與類名相同,只不過沒有前綴“T”。
var
Customer: TCustomer;
2).字段
(1) 命名與格式
字段的命名遵循與變量相同的規則,只不過要加前綴F ,表示這是字段。
(2) 可見性
所有字段必須為私有。如果要在類的作用域之外訪問字段,可借助于類的屬性來實現。
3).方法
(1) 命名與格式
方法的命名遵循與過程和函數相同的規則。
(2) 靜態方法
當你不希望一個方法被派生類覆蓋時,應當使用靜態方法。
(3) 虛擬方法(virtual)與動態方法(dynamic)
當你希望一個方法能被派生類覆蓋,應當使用虛擬方法(virtual)。如果類的方法要被多個派生類直接或間接地使用,則應當用動態方法(dynamic)。例如,某一個類含有一個被頻繁覆蓋的方法,并有100個派生類,則應將方法定義為動態的,這樣可以減少內存的開銷。
(4) 抽象方法(abstract)
如果一個類要創建實例,則不要使用抽象方法。抽象方法只能在那些從不創建實例的基類中使用。
(5) 屬性訪問方法
所有屬性訪問方法應當定義在類的私有或保護部分。屬性訪問方法遵循與過程和函數相同的規則。用于讀的方法應當加“Get”前綴,用于寫的方法應當加“Set”前綴,并且有一個叫Value的參數,其類型與屬性的類型相同。例如:
TSomeClass =
class(TObject)
privatefsomeField: Integer;
protectedfunction GetSomeField: Integer;
procedure SetSomeField(Value: Integer);
public
property SomeField: Integer
read GetSomeField
write SetSomeField;
end;
盡管不是必須,但還是建議你使用寫訪問方法來訪問代表私有字段屬性。
4).屬性
屬性作為私有字段的訪問器,遵循與字段相同的命名規則,只不過沒有F前綴。屬性名應為名詞,而不是動詞。屬性是數據,而方法是動作。數組屬性名應當是復數,而一般的屬性應當是單數。
元件的命名與類的命名類似,只不過當它與其它元件名稱沖突時,你可以加上3個字符的前綴,用以標識公司、個人或其他實體。例如,一個時鐘元件可以這樣聲明:
TddgClock = class(TComponent)
注意,作為前綴的3 個字符要小寫。
元件實例的名稱應當能夠描述其實際意義,這里命名規則使用了一個變更的匈牙利前綴命名規范。使用前綴而不使用后綴的原因是在搜尋時,在對象檢查器和代碼探索器中搜尋構件的名字比搜尋構件的類型更容易。在這個標準中,元件實例名包括兩個部分:前綴和性質標識名。
(1). 元件的前綴
元件的前綴多是表現元件類型的字母縮寫。參見下面表中的元件前綴:
元件類名 | 元件前綴 |
TActionList, TAction表示動作的列表項 | act |
TButton, TSpeedButton, TBitBtn等所有的按鈕類 | btn |
TCheckBox, TDBCheckBox等所有的檢查框 | chk |
TRadioButton單選按鈕類 | rdo |
TToolBar工具條 | tb |
TMainMenu所有的主菜單類 | mm |
TMainMenuItem所有的菜單項類 | mi |
TPopupMenu所有的彈出式菜單類 | pm |
TPopupMenuItem所有的彈出式菜單項類 | pmi |
TLabel, TStaticText等所有用來顯示的標簽類 | lbl |
TPanel等所有的面板類 | pnl |
TPageControl等所有的頁式控件類 | pgc |
TEdit, TMaskEdit等所有的單行編輯框類 | edt |
TMemo, TRichEdit等所有的多行編輯框類 | mmo |
TDrawGrid, TStringGrid等所有的網格類 | grd |
TAnimate等所有的動畫類 | ani |
TImageList等所有的圖片列表類 | il |
TImage等圖片類 | img |
TChart圖表類 | cht |
TComboBox, TDBComboBox等所有的下拉式列表框類 | cbo |
TListBox, TDBList等所有的列表框類 | lst |
TTreeView | tv |
TListView | lv |
THotKey | hk |
TSplitter等所有的分隔符類 | spt |
TOpenDialog等所有的對話框元件類 | dlg |
TTable等所有的數據表類 | tbl |
TQuery等所有的SQL查詢類元件 | qry |
TClientDataSet所有的客戶數據集元件 | cds |
TDataSource | ds |
TDatabase | db |
TSockConnection,TDCOMConnection等連接元件類 | con |
TQuickRep, TFastReport等所有的報表元件類 | rpt |
TDDEClientConv,TDDEClientItem等所有的DDE元件類 | dde |
TMonthCalendar等所有的日歷類 | cal |
TGroupBox等控件類 | grp |
如上所示,元件類型前綴是從分析描述元件的類型性質而來的。通常情況下,下面的規則描述如何定義一個元件類型前綴:
- 從元件類型名中移去T前綴。例如TButton變成Button。
- 除了第一個元音,刪去所有元音字母。例如,Button變成bttn,Edit變成edt。
- 壓縮雙字母。例如,bttn變成btn。
- 如發生沖突,則在某一元件前綴中加入一個元音。例如在TBatton元件的前綴中加入元音變為batn,以區別TButton的前綴。
- 不過,上述規則首先得保證前綴名稱必須符合習慣,做到見名知意,如:TDDEClientConv控件的前綴就是一個例外。
注意:元件的前綴是為了表示出元件的類型,是按鈕,還是標簽等等,因此沒有必要為每一個特別元件類建立一個元件前綴,如: TMyButton的元件前綴仍為btn。
(2). 元件性質標識名
元件性質標識名是元件意圖的描述。例如,一個用于關閉窗體的TButton元件實例可命名為btnClose。一個編輯姓名的元件實例可命名為edtName。
窗體或對話框類型的名稱應當表達出窗體的用途,如果是窗體要加“Tfrm”前綴,如果是對話框要加“Tdlg”,后跟描述性名。例如,About窗體類型名稱為:
TfrmAbout = class(TForm)
主窗體的類型名稱為:
TfrmMain = class(TForm)
客戶登錄窗體的類型名稱為:
TfrmCustomerEntry = class(TForm)
登陸對話框的類型名稱為:
TdlgLogin = class(TForm)
窗體實例的名稱與相應的類型名稱相同,但沒有前綴T 。例如,前面提到的窗體類型與實例的名稱為:
類型名 | 實例名 |
TfrmAbout | frmAbout |
TfrmMain | frmMain |
TfrmCustomerEntry | frmCustomerEntry |
TdlgLogin | dlgLogin |
除非特別原因,只有主窗體才自動生成。其他所有窗體必須從Project Options對話框的自動生成列表中刪除。更進一步信息,請參閱后面幾節。
所有窗體單元都應當含有實例化函數,用于創建、設置、模式顯示和釋放窗體。這個函數將返回由窗體返回的模式結果。傳遞給這個函數的參數遵循參數傳遞的規則。之所以要這樣封裝,是為了便于代碼的重用和維護。
窗體的變量應當從單元中移走,改在窗體實例化函數中作為局部變量定義(注意,要求從Project Options對話框的自動生成列表中移走該窗體。請看前面的內容。
例如,下面的單元文件演示了GetUserData的實例化函數。
Unit UserDataFrm;
Interface
Uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
Type
TfrmUserData = class(TForm)
edtUserName: TEdit;
edtUserID: TEdit;
private
{ Private declarations }
public
{ Public declarations }
end;
function GetUserData(
var aUserName:
String;
var aUserID: Integer):
Word;
implementation
{$R *.DFM}
function GetUserData(var aUserName: String;var aUserID: Integer): Word;
var
frmUserData: TfrmUserData;
begin
frmUserData := TfrmUserData.Create(Application);
frmUserData.Caption:='Getting User Data' ;
Result : = frmUserData.ShowModal;
if Result=mrOK then
begin
aUserName := frmUserData.edtUserName.Text;
aUserID := StrToInt(frmUserData.edtUserID.Text);
end;
finally
frmUserData.Free;
end;
end;
End.
如果一個窗體結構過于復雜,就必須將其分化成為一個主窗體框架以及嵌入到主窗體框架的若干子窗體框架。如:
TfrmMainFrame: TfrmInfoFrame,TfrmEditorFrame
使用窗體框架,主要是為了解決界面和代碼復用問題,以及提高單元代碼的內聚力(劃分后,每一個窗體框架為一個獨立單元),從而提高軟件工程質量。你必須提煉出界面關聯代碼(可復用的)和應用關聯代碼(不能復用的)。
1). 數據模塊的命名標準
數據模塊類型名稱應表達出它的用途,且要加前綴“Tdm”,后跟描述性名稱。例如,Customer數據模塊的類型名稱為:
TdmCustomer = class(TDataModule)
Orders 數據模塊的類型名稱為:
TdmOrder = class(TDataModule)
2). 數據模塊實例的命名標準
數據模塊實例的名稱應當與相應的類型名稱相同,但沒有前綴T 。例如,前面的數據模塊類型、實例名稱如下:
類型名稱 | 實例名 |
TdmCustomer | dmCustomer |
TdmOrder | dmOrder |
建議在所有源文件、項目文件和單元文件使用結構化的文件頭信息。一個文件頭至少應包含以下信息:
{
Copyright @ Year by Authors
}
項目文件的名稱應當具有描述意義。例如,“The Delphi 5 Developer’s Guide Bug Manager ”的項目名稱為DDGBugs.dpr,一個系統信息程序的名稱為SysInfo.dpr。
窗體文件的名稱應當表達出窗體的用途,且具有Frm后綴。例如,About窗體的文件名叫AboutFrm.dfm,主窗體的文件名叫MainFrm.dfm。
數據模塊文件的名稱應當表達出數據模塊的作用,且具有DM后綴。例如,Customers數據模塊的文件名叫CustomersDM.dfm。
遠程數據模塊文件的名稱應當表達出遠程數據模塊的用途。名稱后要加RDM后綴。例如,Customers遠程數據模塊的文件叫CustomersRDM.dfm。
(1) 單元名
單元的名稱應當有描述性。例如,應用程序的主窗體單元叫MaimFrm.pas。
(2) Uses 子句
Interface部分的Uses子句應當只包含該部分需要的單元。不要包含可能由Delphi自動添加的單元名。Implementation部分的Uses子句應當只包含該部分需要的單元,不要有多余的單元。
(3) Interface 部分
Interface部分應當只包含需要被外部單元訪問的類型、變量、過程與函數的聲明。而且,這些聲明應當在Implementation部分之前。
(4) Implementation 部分
Implementation部分包括本單元私有的類型、變量、過程與函數的實現。
(5) Initialization 部分
不要在Initialization部分放置花費時間很多的代碼。否則,將導致應用程序啟動時顯得很慢。
(6) Finalization 部分
確保釋放所有在Initialization部分中分配的資源。
窗體單元文件的名稱與相應的窗體名稱相同,只是要將前綴變成后綴。例如,About窗體的單元名稱叫AboutFrm.pas。主窗體的單元文件名稱叫MainFrm.pas。
數據模塊單元文件的名稱與相應的數據模塊名稱相同。例如,數據模塊單元的名稱叫CustomersDM.pas。
通用單元是用于存放函數庫,一般類型,或常量而非元件的單元。通用單元的名稱應當表達出它的用途,名稱前要加“u”前綴。例如,一個實用調試工具單元的名稱叫uDebugUtilities.pas,包含全局變量的單元名稱叫uCustomerGlobals.pas。
注意,一個項目中單元名稱必須是唯一的。通用單元名不能重名。
(1). 命名
元件單元應放在單獨的路徑中,以表明它們是定義元件的單元。它們一般與項目不放在同一路徑下。單元文件名稱應表達出其內容。
元件單元只能含有一個主要元件,這是指出現在元件選項板上的元件。其他輔助性的元件或對象也可以包含在同一單元中。
(2). 注冊單元
元件的注冊過程應當從元件單元中移走,放在一個單獨的單元中。這個注冊單元用于注冊所有元件、屬性編輯器、元件編輯器、向導等。
元件注冊應當在設計期包中進行。因此,注冊單元應當包含在設計期包而不是運行期包中。建議注冊單元這樣命名:
xxxReg.pas
其中,xxx字符前綴,以標識元件包名稱或公司、個人、其他實體。例如,注冊單元命名為xxxReg.pas。
(1). 運行期包與設計期包
運行期包中應當只包含所需要的單元。那些屬性編輯器和元件編輯器的單元應當放在設計期包中。注冊單元也應當放在設計期包中。
(2). 文件命名標準
包的命名遵循下列模式:
dcliiiDescvvCn.pkg —設計期包
iiiDescvvCn.pkg —運行期包
其中,iii代表一個2-3字符的前綴,用于標識公司、個人或其他需要標識的事情,也可不要;Desc表示該控件包的簡短描述;vv代表包的版本號,你可以根據需要取舍;前綴“dcl”表示設計期包,沒有該前綴表示運行期包;字母“Cn”表示編譯器類型與編譯器版本號,如:Delphi5=D5, Delphi4=D4, CBuilder3=C3...。
注意包名稱中的lib或std分別表示這是設計期包還是運行期包。例如:
dclrbStdCom
PSD5.pkg —Delphi 5的設計期包
rbStdCompsD5.pkg —Delphi 5的運行期包
我們將通過文檔(源程序文件聯機注釋)定義標準的Delphi 類(函數等)的概要設計規范(official Delphi Class API Specification),以及定義Delphi 類(函數等)的編程指南手冊。因此,我們可以以兩種方式來寫程序文檔(注釋),一是作為概要設計的規范,二是作為編程手冊。兩種程序文檔既有差別,又有它們共同的地方,因此,它們可以同時寫在源程序文檔注釋中,它們兩者的差別在下面有說明。
編寫 Delphi 概要設計規范
TODO: <略>
編寫編程指南文檔
在概要設計規范的基礎上,增加了教程,例子程序,等等,并對目錄結構進行了重新設計組織和整理。
為源程序的相關元素添加文檔注釋很簡單,你只需要將注釋放在元素的聲明(Interface)部分(如果是接口函數或類方法)或實現(implementation)部分(如果是私有函數)。例如:
(for Object Pascal)
{ The Sort function sorts the list.} function MyList.Sort(Options: Integer): BOOLEAN; begin [...] end;
(for C++)
// The Sort function sorts the list. bool MyList::Sort(int Options) { [...] }
注釋塊是由一系列的沒有被空行分開的單行注釋構成的,下面就是一個注釋塊:
// This is the first sentence. // This is the second, // and this the third
而下面的注釋則是兩個注釋塊,因為它們之間有一個空行把它們分開了:
// This is the first sentence. // This is the second, // and this the third
許多文檔注釋分析工具(如:Doc-O-Matic)會將注釋塊內的所有的句子自動連接在一起,形成一文字段落,如:
// This is the first sentence. // This is the second, // and this the third
經過分析工具生成的文檔文本為:
This is the first sentence. This is the second, and this the third.
當注釋行前用“##”開頭時,該行注釋將被文檔注釋分析工具忽略,該行不會生成到文檔中。如:
//## This line will be ignored.
包含有如下標識符的注釋塊也不會被生成到文檔中去:
"Ignore Text", "$Log", "$Filename", "$Revision", "$Date", "$Author", "$History", "$Id"
用于描述該單元的用途,作者,功能。放于單元文件的最前面:
{ ##Unit Name: %UNIT% ##Initial Date: %DATE% Summary 該單元的摘要說明。 Description 該單元的詳細說明。 See Also 參閱 Bugs 已知問題。 Internal 內部開發人員參閱,不會對外。 TODO 待作事項。 Author Riceball LEE([email protected]) Riceball LEE([email protected]) Copyright Copyright(C) %YEAR% by Riceball LEE Current Version 當前版本號 History 版本歷史。}unit xxx;
{ ##Procedure: %PROCNAME% ##Date: %DAY%-%MONTHSHORTNAME%-%YEAR% Summary 該函數(屬性)的摘要說明。 Parameters %ARGUMENTS% Returns %RESULT% Conditions 調用該方法(函數)可能需要的條件 Exceptions 該方法(函數)有可能觸發的異常。 Description 該函數(屬性)的詳細說明。 See Also 參閱 Bugs 已知問題。 Internal 內部開發人員參閱,在正式發布的文檔中不會發布。 TODO 待作事項。 Author Riceball LEE([email protected]) Riceball LEE([email protected]) Copyright Copyright(C) %YEAR% by Riceball LEE Current Version 當前版本號 History 版本歷史。}function xxx;
盡管大多數的代碼自動格式化工具能夠幫你重排源程序格式,以及更新保留字和標示符的大小寫,但是這最好在使用版本控制前進行,如果你已經使用了版本控制,建議你不要輕易使用代碼自動格式化工具,哪怕多一個空格,版本控制工具也會認為該行已被修改,從而給程序管理帶來不變。
Artemis Alliance Delphi Coding Standards (E)
Borland官方Object Pascal書寫風格指南 (E)