メタクラスと「クラスプロシージャ」
メタクラスはすべて「クラスプロシージャ」に関するものです。基本から始めるclass
:
type
TAlgorithm = class
public
class procedure DoSomething;virtual;
end;
DoSomething
は、 TALgorithmのインスタンスなしで呼び出すことができるためですclass procedure
(他のグローバルプロシージャと同じように動作します)。できるよ:
TAlgorithm.DoSomething; // this is perfectly valid and doesn't require an instance of TAlgorithm
この設定が完了したら、いくつかの代替アルゴリズムを作成し、すべてが基本アルゴリズムの一部を共有します。このような:
type
TAlgorithm = class
protected
class procedure DoSomethingThatAllDescendentsNeedToDo;
public
class procedure DoSomething;virtual;
end;
TAlgorithmA = class(TAlgorithm)
public
class procedure DoSomething;override;
end;
TAlgorithmB = class(TAlgorithm)
public
class procedure DoSomething;override;
end;
これで、1つの基本クラスと2つの子孫クラスができました。次のコードは、メソッドを「クラス」メソッドとして宣言したため、完全に有効です。
TAlgorithm.DoSomething;
TAlgorithmA.DoSomething;
TAlgorithmB.DoSomething;
タイプを紹介しましょうclass of
:
type
TAlgorithmClass = class of TAlgorithm;
procedure Test;
var X:TAlgorithmClass; // This holds a reference to the CLASS, not a instance of the CLASS!
begin
X := TAlgorithm; // Valid because TAlgorithmClass is supposed to be a "class of TAlgorithm"
X := TAlgorithmA; // Also valid because TAlgorithmA is an TAlgorithm!
X := TAlgorithmB;
end;
TAlgorithmClassは、他のデータ型と同じように使用できるデータ型であり、変数に格納して、パラメーターとして関数に渡すことができます。言い換えれば、これを行うことができます:
procedure CrunchSomeData(Algo:TAlgorithmClass);
begin
Algo.DoSomething;
end;
CrunchSomeData(TAlgorithmA);
この例では、プロシージャCrunchSomeDataは、TAlgorithmの子孫である限り、アルゴリズムの任意のバリエーションを使用できます。
この動作が実際のアプリケーションでどのように使用されるかの例を次に示します。法によって定義されたアルゴリズムに従っていくつかの数値を計算する必要がある給与タイプのアプリケーションを想像してみてください。法則が変更されることがあるため、このアルゴリズムは時間とともに変更されると考えられます。私たちのアプリケーションは、現在の年(最新の計算機を使用)と他の年の両方の給与を、古いバージョンのアルゴリズムを使用して計算する必要があります。物事は次のようになります。
// Algorithm definition
TTaxDeductionCalculator = class
public
class function ComputeTaxDeduction(Something, SomeOtherThing, ThisOtherThing):Currency;virtual;
end;
// Algorithm "factory"
function GetTaxDeductionCalculator(Year:Integer):TTaxDeductionCalculator;
begin
case Year of
2001: Result := TTaxDeductionCalculator_2001;
2006: Result := TTaxDeductionCalculator_2006;
else Result := TTaxDeductionCalculator_2010;
end;
end;
// And we'd use it from some other complex algorithm
procedure Compute;
begin
Taxes := (NetSalary - GetTaxDeductionCalculator(Year).ComputeTaxDeduction(...)) * 0.16;
end;
仮想コンストラクター
Delphiコンストラクタは「クラス関数」のように機能します。メタクラスがあり、メタクラスが仮想コンストラクターについて知っている場合、子孫型のインスタンスを作成できます。これは、「追加」ボタンを押したときに新しいアイテムを作成するためにTCollectionのIDEエディターによって使用されます。これを機能させるために必要なすべてのTCollectionは、TCollectionItemのMetaClassです。