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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重构以避免在使用抽象类而不是接口时进行多重继承相关的知识,希望对你有一定的参考价值。

我正在用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. 从本质上讲,我希望有一个“有一个”解决方案来解决多重“一个”的困境。

感谢您阅读这篇文章!

答案

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

这听起来像是你闻到了什么东西,它不是很好......你可以尝试隐藏气味,并为其他人找出挥之不去的气味的借口,或者你可以开始研究问题的核心(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”部分,那么将会有一种干净(足够)的方式来实现它。这可能意味着更多样板代码,更多源文件,更多类或其他一些虚假问题,但它将无限可维护,可重复使用,可测试,并且您很快就会注意到原始气味已经消失的某个地方。 。

以上是关于重构以避免在使用抽象类而不是接口时进行多重继承的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有多重继承的情况下避免代码重复(即在 java 中)?

区块链开发之Solidity编程基础合约继承抽象合约接口

区块链开发之Solidity编程基础合约继承抽象合约接口

工厂模式和抽象工厂模式区别

12:抽象类,接口,多重继承

重构