gpt4 book ai didi

Delphi 类引用...又名元类...何时使用它们

转载 作者:行者123 更新时间:2023-12-03 14:36:12 26 4
gpt4 key购买 nike

我已阅读官方文档,并且了解什么是类引用,但我无法理解何时以及为何与替代方案相比,它们是最佳解决方案。

文档中引用的示例是 TCollection,它可以使用 TCollectionItem 的任何后代进行实例化。使用类引用的理由是它允许您调用在编译时类型未知的类方法(我假设这是 TCollection 的编译时)。我只是不明白使用 TCollectionItemClass 作为参数如何优于使用 TCollectionItem。 TCollection 仍然能够保存 TCollectionItem 的任何后代,并且仍然能够调用 TCollectionItem 中声明的任何方法。不是吗?

将其与通用集合进行比较。 TObjectList 似乎提供与 TCollection 几乎相同的功能,并具有类型安全的附加优点。您无需从 TCollectionItem 继承来存储对象类型,并且可以根据需要将集合创建为特定类型。如果您需要从集合中访问项目的成员,您可以使用通用约束。除了 Delphi 2009 之前的程序员可以使用类引用这一事实之外,还有其他令人信服的理由在通用容器上使用它们吗?

文档中给出的另一个示例是将类引用传递给充当对象工厂的函数。在本例中,是一个用于创建 TControl 类型对象的工厂。它并不明显,但我假设 TControl 工厂正在调用传递给它的后代类型的构造函数,而不是 TControl 的构造函数。如果是这种情况,那么我至少开始看到使用类引用的一些原因。

所以我想我真正想了解的是类引用何时何地最合适,以及他们向开发人员购买什么?

最佳答案

元类和“类过程”

元类都是关于“类过程”的。从基本的开始:

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 的元类。

关于Delphi 类引用...又名元类...何时使用它们,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3372981/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com