gpt4 book ai didi

delphi - 如何链接 "parallel"类层次结构?

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

我有一个小的类层次结构,其中每个类对应于某个 TComponent 后代(例如基类 TDefaultFrobber 及其后代 TActionFrobber 和 TMenuItemFrobber,分别对应于 TComponent、TCustomAction 和 TMenuItem)。现在我想要一个像这样的工厂(?)函数:

function CreateFrobber(AComponent: TComponent): IFrobber;
begin
if AComponent is TCustomAction then
Result := TActionFrobber.Create(TCustomAction(AComponent))
else if AComponent is TMenuItem then
Result := TMenuItemFrobber.Create(TMenuItem(AComponent))
else
Result := TDefaultFrobber.Create(AComponent);
end;

我可以以某种方式重构它以使用虚拟函数或类似的东西来代替 if-else 级联或 RTTI 吗?

编辑:我现在的解决方案:

unit Frobbers;

interface

uses
Classes;

type
IComponentFrobber = interface
end;

TComponentFrobberClass = class of TComponentFrobber;

TComponentFrobber = class(TInterfacedObject, IComponentFrobber)
strict private
FComponent: TComponent;
protected
constructor Create(AComponent: TComponent);
property Component: TComponent read FComponent;
public
class function FindFrobberClass(AComponentClass: TComponentClass): TComponentFrobberClass; overload; static;
class function FindFrobberClass(AComponent: TComponent): TComponentFrobberClass; overload; static;
class procedure RegisterFrobber(AComponentClass: TComponentClass; AFrobberClass: TComponentFrobberClass); static;
end;

implementation

uses
ActnList,
Menus;

type
TComponentFrobberRegistryItem = record
ComponentClass: TComponentClass;
FrobberClass: TComponentFrobberClass;
end;

var
FComponentFrobberRegistry: array of TComponentFrobberRegistryItem;

class function TComponentFrobber.FindFrobberClass(AComponentClass: TComponentClass): TComponentFrobberClass;
var
i: Integer;
begin
// Search backwards, so that more specialized frobbers are found first:
for i := High(FComponentFrobberRegistry) downto Low(FComponentFrobberRegistry) do
if FComponentFrobberRegistry[i].ComponentClass = AComponentClass then
begin
Result := FComponentFrobberRegistry[i].FrobberClass;
Exit;
end;
Result := nil;
end;

constructor TComponentFrobber.Create(AComponent: TComponent);
begin
inherited Create;
FComponent := AComponent;
end;

class function TComponentFrobber.FindFrobberClass(AComponent: TComponent): TComponentFrobberClass;
var
i: Integer;
begin
// Search backwards, so that more specialized frobbers are found first:
for i := High(FComponentFrobberRegistry) downto Low(FComponentFrobberRegistry) do
if AComponent is FComponentFrobberRegistry[i].ComponentClass then
begin
Result := FComponentFrobberRegistry[i].FrobberClass;
Exit;
end;
Result := nil;
end;

class procedure TComponentFrobber.RegisterFrobber(AComponentClass: TComponentClass;
AFrobberClass: TComponentFrobberClass);
var
i: Integer;
begin
Assert(FindFrobberClass(AComponentClass) = nil, 'Duplicate Frobber class');
i := Length(FComponentFrobberRegistry);
SetLength(FComponentFrobberRegistry, Succ(i));
FComponentFrobberRegistry[i].ComponentClass := AComponentClass;
FComponentFrobberRegistry[i].FrobberClass := AFrobberClass;
end;

function CreateComponentFrobber(AComponent: TComponent): IComponentFrobber;
var
FrobberClass: TComponentFrobberClass;
begin
FrobberClass := TComponentFrobber.FindFrobberClass(AComponent);
Assert(FrobberClass <> nil);
Result := FrobberClass.Create(AComponent);
end;

type
TActionFrobber = class(TComponentFrobber);
TMenuItemFrobber = class(TComponentFrobber);

initialization
TComponentFrobber.RegisterFrobber(TCustomAction, TActionFrobber);
TComponentFrobber.RegisterFrobber(TMenuItem, TMenuItemFrobber);
end.

感谢 Cesar、Gamecat 和 mghie。

最佳答案

如果您使用虚拟构造函数创建一个类并为该类创建一个类类型。您可以根据组件类名称创建查找列表。

示例:

type
TFrobber = class
public
constructor Create; virtual;

class function CreateFrobber(const AComponent: TComponent): TFrobber;
end;
TFrobberClass = class of TFrobber;

type
TFrobberRec = record
ClassName: ShortString;
ClassType: TFrobberClass;
end;

const
cFrobberCount = 3;
cFrobberList : array[1..cFrobberCount] of TFrobberRec = (
(ClassName : 'TAction'; ClassType: TActionFrobber),
(ClassName : 'TButton'; ClassType: TButtonFrobber),
(ClassName : 'TMenuItem'; ClassType: TMenuItemFrobber)
);

class function TFrobber.CreateFrobber(const AComponent: TComponent): TFrobber;
var
i : Integer;
begin
Result := nil;
for i := 1 to cFrobberCount do begin
if AComponent.ClassName = cFrobberList[i].ClassName then begin
Result := cFrobberList[i].ClassType.Create();
Exit;
end;
end;
end;

您当然也可以使用动态列表(字典),但是您必须以某种方式注册每个组合。

更新

对Mghie的言论进行评论。

你说得完全正确。但这不可能没有真正丑陋的伎俩。现在,您必须使用单元的初始化/终结部分来注册类。但是向类添加初始化/终结类方法会很酷。这些必须与单元的初始化(和终结)一起调用。像这样:

class 
TFrobber = class
private
initialization Init; // Called at program start just after unit initialization
finalization Exit; // called at program end just before unit finalization.
end;

关于delphi - 如何链接 "parallel"类层次结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/503079/

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