文档中引用的示例是TCollection,可以使用TCollectionItem的任何后代实例化.使用类引用的理由是它允许您在编译时调用类型未知的类方法(我认为这是TCollection的编译时间).我只是看不到如何使用TCollectionItemClass作为参数优于使用TCollectionItem. TCollection仍然能够保存TCollectionItem的任何后代,并且仍然可以调用在TCollectionItem中声明的任何方法.不是吗
将其与通用集合进行比较. TObjectList似乎提供与TCollection功能相同的功能,具有类型安全性的附加优点.您不需要从TCollectionItem继承,以便存储您的对象类型,您可以根据需要将集合设置为特定类型.如果您需要从集合中访问项目的成员,您可以使用通用约束.除了在Delphi 2009之前的程序员可以使用类引用的事实上,还有其他令人信服的理由将它们用在通用容器上吗?
文档中给出的另一个例子是将类引用传递给一个充当对象工厂的函数.在这种情况下,用于创建TControl类型的对象的工厂.它不是很明显,但我假设TControl工厂正在调用传递给它的后代类型的构造函数,而不是TControl的构造函数.如果是这种情况,那么我开始看到使用类引用的至少一些原因.
所以我想我真正想知道的是什么时候和哪里的类引用是最合适的,他们买什么开发商?
解决方法
MetaClasses都是关于“类程序”的.从基础课开始:
type TAlgorithm = class public class procedure DoSomething;virtual; end;
因为DoSomething是一个类过程,我们可以在没有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;
我们来介绍一下类别:
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.