【问题标题】:refactoring to avoid multiple inheritance when using abstract class instead of interface在使用抽象类而不是接口时进行重构以避免多重继承
【发布时间】:2018-08-10 07:06:20
【问题描述】:

我正在用 C# 编程。我的班级设计变得相当复杂。在许多情况下,我试图尽可能避免继承;例如,我更喜欢“has-a”设计而不是“is-a”设计。

我相信我的设计会遇到指定的最终设计是多重继承的情况。我知道多重继承的禁忌,Java 和 C# 都不允许这样做。

我会尝试写一些伪代码来说明我的情况。

假设在我的开发应用程序中,我想区分屏幕上可见的项目和不可见的项目。我将创建一个类“DisplayObject”,它是要显示的所有项目的根类。

我有一个“Button”类,它将继承自 DisplayObject。

class Button : DisplayObject

但是,我想创建一个抽象类“可点击”。 (我知道,在这一点上,有些人可能会说“使用接口”,例如 IClickable。但现在,把这个建议放在一边。)

Clickable 是一个抽象类,我想提供一些默认功能。 Button 类(显然)不能同时继承自 DisplayObject 和 Clickable。

一个想法可能是让 Clickable 继承自 DisplayObject,然后 Button 继承自 Clickable。

class Clickable : DisplayObject

class Button : Clickable

这似乎是个好主意,因为我想创建一个也可点击的 Link 类。 "Link" 类可以继承自 Clickable。

没有详细说明这可能导致什么样的“臭”代码增长,我似乎正在努力使用装饰器模式。但据我记忆,装饰器模式是这样实现的:

class Button : ClickableDecorator<DisplayObject>

我也不喜欢那样。特别是如果我打算在我的类定义中添加很多“装饰器”。

所以我可能会倾向于尝试将伪装饰器列表作为 Button 类的成员:

public List<Decorator> Decorators { get; set; }

但这仍然会让人感到困惑。

总结(希望找到解决方案):

  1. 我不想做太多的“预重构”(重构提前完成 实际上适得其反的时间)。
  2. 我不想采用简单的推荐解决方案,因为那样 会引起很多麻烦,这需要 大量重构。
  3. 基本上,我希望有一个“有”的解决方案 多重“is-a”困境。

感谢您阅读本文!

【问题讨论】:

  • 您可能想查看 WPF 类树
  • 或许可以考虑构图

标签: c# inheritance interface abstract-class member


【解决方案1】:

我知道你的代码是否有异味的好方法是闻一闻。如果认为它有气味,那么很有可能其他鼻子不通的人也认为它有气味。

在我看来,你好像在闻到什么东西,而且味道不好。你可以试着隐藏这种气味,并为其他人找借口说那是什么挥之不去的气味,或者你可以开始研究(恕我直言)由以下评论代表的问题:

但是,我想创建一个抽象类“可点击”。 (我知道,在这一点上,有些人可能会说“使用接口”,例如 IClickable。但现在,把这个建议放在一边。)

为什么要把它放在一边?这是一个完全有效的想法(我不是说,我是说考虑一下)。

正如this answer 所描述的,接口描述的是can-do,继承描述的是is-a。因此,“is-a”DisplayObject 和“can-do”Click() 的 Button 是您应该考虑的一种思考方式。

class Button : DisplayObject, IClickable

这很方便,因为它允许您将按钮和其他可点击项添加到 List&lt;IClickable&gt; 以进行迭代,或者设计一个处理程序来接受任何实现 IClickable 的内容。

另一种思考方式是使用多层继承:

class ClickableDisplayObject : DisplayObject { ... }

class Button : ClickableDisplayObject { ... }

所有可显示的东西都不必直接派生自DisplayObject

如果不知道您要解决什么具体问题,很难给您更多建议,但最后我想说:

  1. 如果您担心所谓的预重构,并且不想进行太多重构,那么请仔细看看为什么您做出了迄今为止所做的决定,并考虑到尽管多年来有数十亿行代码,但大多数 C# 世界并没有为您的确切问题而苦苦挣扎是有原因的。如果您认为需要多重继承,那您就大错特错了。
  2. 暂时忘记 has-a。您在顶部和底部再次提到它,但我还没有看到一个很好的解释来说明它实际上是一个问题,以及为什么继承和接口不能以一种很好、干净的方式为您解决它。李>
  3. 在没有多重继承的情况下会有一个干净(足够)的方法来做到这一点,但前提是您愿意遵循良好的编码原则,例如SOLID,尤其是“S”部分。这可能意味着更多样板代码、更多源文件、更多类或其他一些虚假的问题,但它将无限地更具可维护性、可重用性、可测试性,并且您很快就会注意到原始气味已经消失的地方。 .

【讨论】:

  • 我会查看提供的链接。我想避免使用接口的主要原因是我不想重复代码;即,我计划使用定义了最少功能的抽象类。我认为复合设计模式的一些方法会很有用。
猜你喜欢
  • 2012-03-25
  • 2011-03-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-04
  • 2016-11-05
  • 2017-11-27
  • 2018-04-05
  • 2019-01-10
相关资源
最近更新 更多