【问题标题】:Add Fields and Methods to classes that inherit from same base without modifying base class将字段和方法添加到从相同基类继承的类而不修改基类
【发布时间】:2016-06-22 11:27:35
【问题描述】:

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

例如 TcxLabel 和 TcxDBLabel(来自 DevExpress)。 两者都继承自同一个基类。

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

我今天的做法:

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

 

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

所以基本上我必须写两次。

实现它的一种方法是修改这两个控件继承自的基类。 但这不是一个选项 - 不应修改 DevExpress 类/包。

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

【问题讨论】:

  • AFAIK 没有干净的方法可以做到这一点。
  • @MartynA 类助手不允许我声明新字段,只能声明方法。
  • 啊,是的,对不起,我有一个“高级时刻”。
  • 有人似乎对答案不满意......但是,OP 想要的东西是不可行的。
  • 您可以编写一个包含这些字段和方法的 TcxLabelExt 类,并将这样的 TcxLabelExt 添加到两种 tMycx... 类型,而不是添加这些字段和方法到这两种标签类型.然后你只需要编写一次扩展功能。您必须手动处理包含的扩展,但这可能要容易得多。

标签: delphi pascal lazarus


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

    有一种方法,尽管它仅在您只需要基类中可用的内容时才会起作用。 例如,如果 TcxDBLabel 继承自 TcxLabel,那么只要您只使用 TcxDBLabel 的 TcxLabel 部分(字段、方法和属性),就可以向两者添加方法(松散地说)。

    我指的是类型转换

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

    所以如果你像这样创建一个子类:

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

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

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

    就像我说的那样,在 DoSomething 方法中您不会使用 TcxDBLabel 的任何细节,但您将能够使用基类资源。

    【讨论】:

      【解决方案3】:

      您能否继承一次虚拟类(即“您的”),在其中定义新字段,然后从那里继承两个新类?

      基于 cmets 编辑:

      你可以试试这样。

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

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

      然后像这样称呼它

      cxLabel1.MyStuff.DoSomething();
      

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

      【讨论】:

      • 当你尝试用一些代码充实这个想法时,你会意识到它是不可行的。
      • 好吧,我对主题行中的“相同基类”感到困惑。显然,他继承自两个基类。
      • @Jur:是的,他继承了上面提到的两个类。但是这两个派生自同一个基类。
      • 您的更新与我建议的类似,尽管我会将其设为具有适当 getter 和 setter 的属性。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-23
      相关资源
      最近更新 更多