将字段和方法添加到 class 继承自同一基而不修改基 class 的元素

Add Fields and Methods to classes that inherit from same base without modifying base class

在我的应用程序中,我需要向第 3 方控件添加一些额外的功能。

例如 TcxLabel 和 TcxDBLabel(来自 DevExpress)。 两者都继承自相同的基础 class.

对于那些控件,我想添加一些字段和方法。

我今天的做法:

TMycxLabel = class(TcxLabel)
private
  FMyField1: string;
  FMyField2: Integer;
public 
  procedure DoSomething;
end;

TMycxDBLabel = class(TcxDBLabel)
private
  FMyField1: string;
  FMyField2: Integer;
public 
  procedure DoSomething;
end;

所以基本上我必须把所有的东西都写两次。

实现它的一种方法是修改基础 class 这 2 个控件继承自。 但这不是一个选项 - DevExpress classses / packages 不应该被修改。

有没有办法添加实现这个?

您能否继承一次虚拟 class(即 "yours"),在那里定义新字段,然后从那里继承两个新的 classes?

根据评论编辑:

好吧,你可以这样试试。

在你继承的 classes 中,只需添加一个 public 数据成员,它本身就是一个 class,你可以在其中定义你自己的东西......看起来像:

TMycxLabel = class(TcxLabel)
public
  MyStuff: TMyStuff;
end;

TMyStuff = class()
private
  FMyField1: string;
  FMyField2: Integer;
public 
  procedure DoSomething;
end;

然后像

那样称呼它
cxLabel1.MyStuff.DoSomething();

我意识到这并不能完全回答您的问题,并且不适用于几个用例(您不能通过这种方式从 MyStuff 访问 TMycxLabel 的所有属性),但也许您可以避免一些双重编码。

Is there a way to add achieve this?

不,没有。任何可行的解决方案都将基本上等同于您当前的方法。由于您需要与实例关联的状态,因此您实际上需要它成为实例的一部分。这会引导您找到现有的解决方案。

您可以考虑劫持 Tag 之类的字段来存储该状态,但这是错误的,因为 Tag 保留供该类型的使用者使用。其他可能的解决方案可能涉及维护一个单独的列表,该列表将实例映射到此附加状态。你可以让它工作,但在我看来,它太笨重了,以至于比替代方案更糟糕。

最有效的方法是将字段添加到公共基础class,但您已经排除了这种可能性,因为它涉及修改第三方代码。

有一种方法,但只有当您只需要基础 class 中可用的内容时它才会起作用。 例如,如果 TcxDBLabel 继承自 TcxLabel,则只要您只使用 TcxDBLabel 的 TcxLabel 部分(字段、方法和属性),就可以为两者添加一个方法(松散地说)。

我指的是类型转换

我应该警告,这种做法的使用并非自愿的。许多开发人员认为 typecasting 是一种不好的做法,而我本人倾向于将其用作最后的手段。但是,我会把关于天气的哲学讨论留给你,你应该或不应该使用它。

因此,如果您像这样创建子class:

THcxLabel = Class(TcxLabel)
private
  FMyField1: string;
  FMyField2: Integer;
public
  procedure DoSomething;
End;

然后您可以将其添加到任何基于 TcxLabel 的 class 实例,如下所示:

THcxLabel(cxLabel1).DoSomething;
THcxLabel(cxDBLabel1).DoSomething;

就像我说的,在 DoSomething 方法中您无法使用 TcxDBLabel 的任何细节,但您将能够使用基础 class 资源。