元类和“类过程”
元类都是关于“类过程”的。从一个基本的开始class
:
type
TAlgorithm = class
public
class procedure DoSomething;virtual;
end;
因为DoSomething
是 aclass procedure
我们可以在没有 TAlgorithm 实例的情况下调用它(它的行为类似于任何其他全局过程)。我们可以完成这个:
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;
我们现在有一个基类和两个后代类。以下代码完全有效,因为我们将这些方法声明为“类”方法:
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 的后代。
以下是如何在实际应用程序中使用此行为的示例:想象一个工资单类型的应用程序,其中一些数字需要根据 Law 定义的算法进行计算。可以想象这个算法会随着时间的推移而改变,因为法律有时会改变。我们的应用程序需要计算当前年份(使用最新的计算器)和其他年份的薪水,使用旧版本的算法。以下是事情的样子:
// 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 工作所需的所有 TCollection 都是 TCollectionItem 的 MetaClass。