继承与聚合[关闭]

2024-04-05

关于如何在面向对象系统中最好地扩展、增强和重用代码,有两种思想流派:

  1. 继承:通过创建子类来扩展类的功能。重写子类中的超类成员以提供新功能。当超类需要特定接口但不知道其实现时,使方法抽象/虚拟以强制子类“填空”。

  2. 聚合:通过获取其他类并将它们组合成一个新类来创建新功能。为这个新类附加一个公共接口,以便与其他代码实现互操作。

每种方法的好处、成本和后果是什么?还有其他选择吗?

我看到这种辩论经常出现,但我认为没有人问过这个问题 堆栈溢出尚未(尽管有一些相关的讨论)。令人惊讶的是,它在谷歌上却缺乏良好的结果。


问题不在于哪个最好,而在于何时使用什么。

在“正常”情况下,一个简单的问题就足以确定我们是否需要继承或聚合。

  • 如果新班级is或多或少与原来的班级一样。使用继承。新类现在是原始类的子类。
  • 如果新班级必须have原来的班级。使用聚合。新班级现在有原来的班级作为成员。

然而,存在很大的灰色地带。所以我们还需要一些其他的技巧。

  • 如果我们已经使用了继承(或者我们计划使用它),但我们只使用了部分接口,或者我们被迫重写很多功能以保持相关性逻辑。然后我们就闻到了一股难闻的气味,表明我们必须使用聚合。
  • 如果我们已经使用了聚合(或者我们计划使用它),但我们发现我们需要复制几乎所有功能。然后我们就有了指向传承方向的气味。

简而言之。如果部分接口未使用或必须更改以避免不合逻辑的情况,我们应该使用聚合。如果我们需要几乎所有的功能而不需要进行重大更改,那么我们只需要使用继承。如有疑问,请使用聚合。

另一种可能性是,我们有一个类需要原始类的部分功能,这种情况是将原始类拆分为根类和子类。并让新类继承自根类。但你应该小心这一点,不要造成不合逻辑的分离。

让我们添加一个例子。我们有一个“狗”类,其方法有:“吃”、“走”、“吠”、“玩”。

class Dog
  Eat;
  Walk;
  Bark;
  Play;
end;

我们现在需要一个“猫”类,它需要“吃”、“走”、“咕噜”和“玩”。所以首先尝试从 Dog 扩展它。

class Cat is Dog
  Purr; 
end;

看起来不错,但是等等。这只猫会叫(爱猫人士会因此杀了我)。一只狂吠的猫违反了宇宙法则。因此我们需要重写 Bark 方法,使其不执行任何操作。

class Cat is Dog
  Purr; 
  Bark = null;
end;

好吧,这可行,但味道很难闻。那么让我们尝试一下聚合:

class Cat
  has Dog;
  Eat = Dog.Eat;
  Walk = Dog.Walk;
  Play = Dog.Play;
  Purr;
end;

好的,这很好。这只猫不再叫了,甚至不再沉默了。但它的内心仍然有一只想要出去的狗。那么让我们尝试第三种解决方案:

class Pet
  Eat;
  Walk;
  Play;
end;

class Dog is Pet
  Bark;
end;

class Cat is Pet
  Purr;
end;

这样就干净多了。没有内狗。而且猫和狗是同一水平的。我们甚至可以引入其他宠物来扩展模型。除非是鱼,或者不会走路的东西。在这种情况下,我们再次需要重构。但这是另一回事了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

继承与聚合[关闭] 的相关文章

  • 生成所有多集大小为 n 的分区的算法

    我一直在试图找出一种方法来生成多重集的所有不同的大小为 n 的分区 但到目前为止却空手而归 首先让我展示一下我想要实现的目标 假设我们有一个输入向量uint32 t std vector
  • C# - 继承WPF布局 - Window from Window

    我的 Window 继承有问题 我不明白问题是什么 我认为 我的布局 MediaLibrary xaml 必须继承 MainWindow 但我不知道该怎么做 有2类 主窗口 xaml
  • 从派生模板类调用函数

    我的基类 Element h class Element public Element virtual Element not sure if I need this virtual Element plus const Element v
  • 如何保证对象只有一个线程

    我有以下代码 class Service public void start creates thread which creates window and goes to message loop void stop sends WM C
  • JavaScript 原型 - 请澄清

    有人可以帮我理解原型属性吗 我不明白原型属性是函数的属性还是函数内部的属性 假设我们创建以下构造函数 Food 此时 函数 Food 具有 Food prototype 属性 由于 Food 是 Object 的实例 因此这意味着 Obec
  • Java继承,扩展类如何影响实际类

    我正在查看 Sun 认证学习指南 其中有一段描述了最终修饰符 它说 如果程序员可以自由地扩展我们所知的 String 类文明 它可能会崩溃 他什么意思 如果可以扩展 String 类 我是否不会有一个名为 MyString 的类继承所有 S
  • 子类构造函数(JAVA)中的重写函数[重复]

    这个问题在这里已经有答案了 为什么在派生类构造函数中调用超类构造函数时 id 0 当创建子对象时 什么时候在堆中为该对象分配内存 在基类构造函数运行之后还是之前 class Parent int id 10 Parent meth void
  • 过程式编程与 OOP 的开发成本?

    我有相当深厚的 OO 背景 OOD 和 OOP 的好处对我来说是第二天性 但最近我发现自己在一家与过程编程习惯相关的开发商店 实现语言具有一些 OOP 功能 但它们没有以最佳方式使用 更新 每个人似乎对这个话题都有自己的看法 我也是如此 但
  • 数据聚合和缓存:如何按时间间隔快速绘制大型时间序列数据集的图表

    我有一个巨大的时间序列数据集 我想绘制图表 时间序列可以追溯到 5 年前 从后端的角度来看 以各种分辨率 间隔 显示这些数据的常用方法是什么 本质上我想绘制这样的数据图表 https bitcoinwisdom com markets bi
  • 从父类调用子类方法

    a doStuff 方法是否可以在不编辑 A 类的情况下打印 B did stuff 如果是这样 我该怎么做 class Program static void Main string args A a new A B b new B a
  • 在数字集合中查找最接近的匹配[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的
  • 防止Java实例化的正确方法[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 虚拟继承如何解决“钻石”(多重继承)的歧义?

    class A public void eat cout lt lt A class B virtual public A public void eat cout lt lt B class C virtual public A publ
  • 哪些不同的术语表示相同的事物(或不同的术语,但人们认为它们表示相同的意思)? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的
  • C++:重写已弃用的虚拟方法时出现弃用警告

    我有一个纯虚拟类 它有一个纯虚拟方法 应该是const 但不幸的是不是 该接口位于库中 并且该类由单独项目中的其他几个类继承 我正在尝试使用这个方法const不会破坏兼容性 至少在一段时间内 但我找不到在非常量方法重载时产生警告的方法 以下
  • 优雅降级 - 何时考虑

    在为使用 AJAX 的应用程序设计和构建 UI 时 您何时考虑优雅降级 对于禁用 JavaScript 或正在使用屏幕阅读器的用户 最后 网站的 AJAX 版本完全完成后 在每个发展阶段 I don t 还有别的事 这些日子 渐进增强 ht
  • 是否可以在 C# 中强制接口实现为虚拟?

    我今天遇到了一个问题 试图重写尚未声明为虚拟的接口方法的实现 在这种情况下 我无法更改接口或基本实现 而必须尝试其他方法 但我想知道是否有一种方法可以强制类使用虚拟方法实现接口 Example interface IBuilder
  • 克隆和引用传递问题

    所以在过去的几天里 我一直在绞尽脑汁地试图让一个类能够正确克隆 问题是克隆不会删除 重做任何引用传递 结果是 主数据对象仍然作为引用传递 从而完全抵消了克隆的效果 这是问题的简化版本 class my class private data
  • 如何使用“instanceof”实现泛型的“equals”方法?

    我有一堂课接受泛型 我想覆盖equals以一种不尴尬的方式 即看起来干净并且代码量最少的东西 但对于非常一般的用例 现在我有这样的事情 public class SingularNode
  • “对象之间通过传递消息进行通信”到底是如何实现的?

    在几本有关面向对象编程的介绍性文本中 我遇到过上述陈述 来自维基百科 在 OOP 中 每个对象都能够接收消息 处理数据 以及发送消息与其他对象相关 并且可以被视为具有独特角色或责任的独立 机器 该语句在代码中到底意味着什么 class A

随机推荐