(《將物件導向的思想貫穿始終-談Delphi開發》之第三篇)
前兩篇討論的是有關封裝性的話題。這裡,想和您說說關於繼承和多態。
繼承和多態是密切相關的。 Object Pascal引進了一種多態的機制,叫重載(Overload),它的想法與物件導向關係不大,這裡不作討論。與物件導向思想密切相關的多態是我們著重要的討論。
多態依賴抽象方法以及虛方法的概念,同時也和繼承密切相關。以為我們往往定義一些底層的對象,然後將其某些實現定義為抽象的,也就是說我們僅僅定義了接口,而沒有定義具體的實現細節。依照這樣的思路,我們也會定義多個派生(繼承)的對象,在這些對像中真正實作那些在祖先類別中未曾實現的細節。這就使得我們先前定義的底層類,具有多態的特性。這種機制的好處在於,我們使用這些類別的時候,只要一套程式碼,就可以完成多種功能。而唯一需要改變的就是創建物件的實例的那一部分。
觀察這樣的一個類別:
TStream = class(TObject)
……
public
function Read(var Buffer; Count: Longint): Longint; virtual; abstract;
function Write(const Buffer; Count: Longint): Longint; virtual; abstract;
……
end;
virual以及abstract保留字顯示了Read以及Write方法是純虛函數。這顯示TStream這個類別並不能被真正使用(不能創建該類別的實例),它只是一個類似於介面的類,它定義了作為TStream類別應當具備以及需要處理的基本功能。而且它還規定,其他從TStream類派生出的類,必須去實現的功能(如Read以及Write等)。
舉例來說,TFileStream,以磁碟檔案應用的方式實作了TStream類別;而TMemoryStream則以記憶體應用的方式實作了TStream類別。現在假設有一個類別TMyClass提供一個SaveToStream的方法:
TMyClass = Class(TObject)
PRocedure SaveToStream(Stream: TStream);
end;
則應用多態的思想,可以有這樣的程式碼:
var
strm: TStream;
MyClass: TMyClass;
begin
strm := TFileStream.Create('abc.txt'); // ß 此處Stream的真正實例類型是TFileStream
MyClass := TMyClass.Create;
MyClass.SaveToStream(strm);
…..
end;
而要將MyClass的內容存放到記憶體中,只需改變
strm := TFileStream.Create('abc.txt');
為:
strm := TMemoryStream.Create;
即可。
多態的使用是需要兩方面的工作,其一當然是類的構架中考慮到了多態,能夠提供實現某種功能的中間類(抽象類);其二,是懂得去運用這些中間類,這個工作體現在定義一些過程,函數的參數。
另外很重要的一點,我想提醒大家的是,類別的規劃是很重要的,在物件導向程式設計的時代,類別的框架很大程度上決定了程式的框架,決定了軟體開發的成敗。結構清楚,層次分明的類別架構,不僅易於功能劃分與擴展,同時也更易於程式碼的維護。而在這之中,應用繼承和多態的思想,引入抽象類,引入中間類,是較為可取的一種方法。
以下列出Delphi中提供的一部分抽象類別與具體類別:
抽象類別派生的具體類別
TStream TFileStream,TMemoryStream;
TCustomIniFile TIniFile, TMemIniFile,TRegistryIniFile;
TStrings TStringList,TMemoStrings,TListBoxStrings;
還有很多,等你我去發現。這裡最常用的是TStream,而最令我驚異的是TCustomIniFile,它的TRegistryIniFile讓你可以用存取IniFile的方式來存取登錄檔!這使得我可以用一套程式碼,實現寫入註冊表和寫Ini檔案的功能。這其中的技術雖然簡單,但是它的意義非同凡響!
(未完,待續)
更多文章