重构以避免在使用抽象类而不是接口时进行多重继承

问题描述 投票:0回答:1

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

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

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

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

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

class Button : DisplayObject

但是,我想创建一个抽象类“Clickable”。 (我知道,在这一点上,有些人可能会说“使用界面”,例如IClickable。但是现在,请将该建议放在一边。)

Clickable的意思是抽象类,我希望提供一些默认功能。 Button类(显然)不能从DisplayObject和Clickable继承。

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

class Clickable : DisplayObject

class Button : Clickable

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

如果没有详细说明这可能会导致什么样的“臭”代码增长,我似乎正在努力使用Decorator模式。但是从我记忆中,Decorator模式实现如下:

class Button : ClickableDecorator<DisplayObject>

我也不喜欢这样。特别是如果我计划在我的类定义中添加很多“Decorator”。

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

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

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

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

  1. 我不想做太多的“Prefactoring”(提前完成的重构,实际上是适得其反的)。
  2. 我不想采用简单的推荐解决方案,因为这将导致很多麻烦,这将需要大量的重构。
  3. 从本质上讲,我希望有一个“有一个”解决方案来解决多重“一个”的困境。

感谢您阅读这篇文章!

c# inheritance interface abstract-class member
1个回答
1
投票

我很好地知道你的代码是否闻到了嗅觉。如果你认为它有气味,那么其他所有半工作鼻子的人都认为它有气味。

这听起来像是你闻到了什么东西,它不是很好......你可以尝试隐藏气味,并为其他人找出挥之不去的气味的借口,或者你可以开始研究问题的核心(imho)由以下评论代表:

但是,我想创建一个抽象类“Clickable”。 (我知道,在这一点上,有些人可能会说“使用界面”,例如IClickable。但是现在,请将该建议放在一边。)

为什么要放在一边?这是一个完全有效的思考(我不是说这样做,我说是考虑它)。

正如this answer所描述的,接口是关于描述can-do,继承描述的是-a。所以一个按钮“is-a”DisplayObject和“can-do”Click()是一种思考它的方式,也许你应该考虑。

class Button : DisplayObject, IClickable

这很方便,因为它允许您,例如将按钮和其他可点击按钮添加到List<IClickable>进行迭代,或者设计一个处理程序,它可以执行任何实现IClickable的操作。

考虑它的另一种方法是使用多层继承:

class ClickableDisplayObject : DisplayObject { ... }

class Button : ClickableDisplayObject { ... }

所有可展示的东西都不必直接来自DisplayObject

在不知道你想要解决什么具体问题的情况下,很难再给你任何建议,但最后我会说:

  1. 如果你担心所谓的预制,并且你不想进行太多的重构,那么就要仔细看看为什么你做出了你迄今做出的决定,并考虑到这可能是大多数的原因。尽管多年来有数十亿行代码,但C#世界并没有为你的确切问题而烦恼。如果你认为你需要多重继承,那你就错了。
  2. 暂时忘记了。你在顶部和底部再次提到它,但我还没有看到它是如何实际问题的一个很好的解释,以及为什么继承和接口无法以一种漂亮,干净的方式为你解决它。
  3. 如果你愿意遵循SOLID这样的良好编码原则,特别是“S”部分,那么将会有一种干净(足够)的方式来实现它。这可能意味着更多样板代码,更多源文件,更多类或其他一些虚假问题,但它将无限可维护,可重复使用,可测试,并且您很快就会注意到原始气味已经消失的某个地方。 。
© www.soinside.com 2019 - 2024. All rights reserved.