2013-07-12 117 views
2

從抽象基類創建子類的最佳方法。從抽象基類創建子類的最佳方法

在我的項目中,我有這樣的基類抽象和兩個子類。

TbaseClass=class 
public 
    procedure Doit;virtual;abstract; 
    procedure Calculate;virtual;abstract; 


Tchild1class=class(TbaseClass) 
.. 
protected 
    procedure CalcArea;virtual; 
public 
    procedure Doit;override; 
    procedure Calculate;override; 


Tchild2class=class(Tchild1class) 
protected 
    procedure CalcArea;override; 

在我的buttonclick代碼中,我以這種方式創建所需的childclass,並且正在工作。

..... 
var 
T:TBaseClass; 
begin 
    case OP of 
    1: T:=Tchild1class.Create; 
    2: T:=TChild2Class.Create; 
T.Doit; 
T.Calculate; 
end; 

我的問題是下一個。 我可以在我的基抽象類中創建一個構造函數創建過程,這取決於int參數生成所需的子類? 例如:

constructor TBaseClass.Create(OP:integer); 
begin 
inherited; 
case OP of 
    1: Tchild1class.Create; ///>>>??? 
    2: TChild2Class.Create; //>>>>??? 
end; 

這是可能的嗎?

什麼是最好的方法來做到這一點?

回答

10

不,這是不可能的。一旦構造函數開始運行,正在創建的對象的類就被修復了。一個對象不能改變它的類,即使在施工過程中也是如此。

您可以編寫一個工廠函數,它接受整數參數並選擇實例化哪個後代類。這將很像你提出的無效構造函數,就像獨立函數或類方法而不是構造函數一樣。

你也可以寫,只是返回的功能,然後你也可以在以後實例化它,就像這樣:

type 
    TBaseClassClass = class of TBaseClass; 

function GetDescendantClass(op: Integer): TBaseClassClass; 
begun 
    case op of 
    1: Result := TChild1Class; 
    2: Result := TChild2Class; 
    else Assert(False); 
    end; 
end; 

var 
    DescendantClass: TBaseClassClass; 

DescendantClass := GetDescendantClass (op); 
T := DescendantClass.Create; 
T.DoIt; 

使用該技術,它有時是有用的,使構造函數是虛擬的,但這不是要求。

+0

Thx爲答案,但需要聲明TBaseClassClass類型?函數GetDescendantClass不能直接返回TBaseClass ?. –

+1

我已經向你展示了它的聲明;你不需要更多的東西來聲明它。如果返回類型是'TBaseClass',那麼你將有一個工廠函數,並且你需要返回一個*實例*,而當返回類型是'TBaseClassClass'時,你返回一個*類*並在稍後創建實例。 'TBaseClassClass'就是所謂的*元類* - 查看它。 –