6

我想对以下问题提出一些建议:假设您想为 VCL 控件编写适配器。所有适配器都应该具有相同的基类,但在包装特殊控件方面有所不同(例如,从 TEdit 获取值与从 TSpinEdit 获取值不同)。所以第一个想法是创建一个类层次结构

TAdapter = class
end;

TEditAdapter = class (TAdapter)
end;

TSpinEditAdapter = class (TAdapter)
end;

现在我想介绍一个字段来保存对 vcl 控件的引用。在我的特殊适配器中,我当然希望使用具体的子类。但是 Base 类也应该包含一个引用(例如,如果我想使用适配器使控件可见)。

可能性 1(属性访问器中的向下转换):

TAdapter = class
protected
  FCtrl : TControl;
end;

TEditAdapter = class (TAdapter)
  public
    property Control : TEdit read GetControl write Setcontrol;
end;
{...}
function TEditAdapter.GetControl : TEdit;
begin
  Result := FCtrl as TEdit;
end;

因此,如果我实现了一个特定的方法,我将使用属性 Control,如果我在我的基类中做某事,我将使用受保护的字段。

可能性 2(使用通用基类):

TAdapter = class
end;

TAdapter <T : TControl> = class (TAdapter)
protected
  FCtrl : T;
end;

TEditAdapter = class (TAdapter <TEdit>)
end;

您更喜欢哪种解决方案?还是有第三种更好的解决方案?

亲切的问候,

基督教

4

2 回答 2

4

您不能使用泛型来解决此问题,因为您将处于以下两种情况之一:

  • 您想要“适应”的属性或方法(Text例如属性)是在祖先类中定义的。在这种情况下,您不需要泛型,因为您可以为祖先使用一个适配器并为所有后代解决问题。
  • 属性或方法由你要适配的类引入。在这种情况下,您不能使用泛型,因为为了访问属性或方法,您需要该给定类型的泛型类型约束。例子。假设您想要一个用于Text. TMyClass让我们假设TMyClass是介绍该Text属性的人。为了访问它,您需要将泛型类型声明为TGeneric<T:TMyClass>并且这实际上不是泛型的。

在我看来,最好的选择是为每个类编写特定的适配器,就像您的第一个选项一样。您也许可以使用 RTTI 技巧使您的第一个选项更易于实施,但我不确定这是否值得。

于 2011-06-17T10:13:58.810 回答
0

泛型版本可以避免一些重复的代码,至少在 TAdapter 类中是这样。通过使用该T类型,它将允许大量共享代码。

另一方面,由于 VCL 层次结构,大多数使用的属性和方法已经在TControl. 所以我不确定在非泛型实现中会有这么多重复的代码。

我怀疑非泛型版本会产生更少的代码和 RTTI,因为当前的泛型实现往往不会复制源代码,而是增加 exe 大小。

恕我直言,基于泛型的设计将为实现添加更多抽象,但非泛型可能更接近它将适应的 VCL 层次结构。

因此,对于您的特定情况(映射 VCL),由于您的尝试是映射非泛型类,我宁愿研究非泛型解决方案。

对于另一种(非基于 VCL 的)适配器架构,我可能会建议一个纯通用的实现,自下而上。

于 2011-06-17T09:56:37.213 回答