language-agnostic - 子类导致父类(super class)中的意外行为——OO 设计问题

标签 language-agnostic oop overriding subclass

虽然我在 ObjC 中编码,但这个问题是有意与语言无关的 - 它应该适用于大多数 OO 语言

假设我有一个“Collection”类,我想创建一个继承自“Collection”的“FilteredCollection”。过滤器将在对象创建时设置,从它们开始,该类的行为就像一个“集合”,过滤器应用于其内容。

我以明显的方式和子类 Collection 做事。我覆盖了所有的访问器,并认为我已经完成了一项非常出色的工作——我的 FilteredCollection 看起来应该像一个集合一样,但其中的对象与我的过滤器相对应的对象被过滤给用户。我想我可以愉快地创建 FilteredCollections 并将它们作为 Collections 在我的程序中传递。

但我来测试 - 哦不 - 它不起作用。深入调试器,我发现这是因为某些方法的 Collection 实现正在调用重写的 FilteredCollection 方法(例如,Collection 在迭代其对象时依赖于“count”方法,但现在它正在获取过滤后的计数,因为我覆盖了 count 方法以提供正确的外部行为)。

这里有什么问题?为什么感觉有些重要原则被违反了,尽管它也感觉像 OO '应该' 以这种方式工作?这个问题的一般解决方案是什么?有吗?

顺便说一句,我知道这个问题的一个很好的“解决方案”是在我将它们放入集合之前过滤对象,并且根本不需要更改 Collection,但我问的是一个更普遍的问题比这 - 这只是一个例子。更普遍的问题是不透明父类(super class)中的方法依赖于可能被子类更改的其他方法的行为,以及在您想要子类化对象以更改此类行为的情况下该怎么做。

最佳答案

Collection你继承的有一定的契约。类的用户(包括类本身,因为它可以调用自己的方法)假设子类遵守契约。如果幸运的话,契约(Contract)会在其文档中明确无误地指定...

例如,合约可以说:“如果我添加一个元素 x ,然后遍历集合,我应该得到 x 返回”。看来你的FilteredCollection实现违反了该契约(Contract)。

这里还有一个问题:Collection应该是一个接口(interface),而不是一个具体的实现。一个实现(例如 TreeSet )应该实现那个接口(interface),当然也遵守它的契约。

在这种情况下,我认为正确的设计是不继承 Collection ,而是创建 FilteredCollection作为围绕它的“包装器”。大概FilteredCollection不应执行 Collection接口(interface),因为它不遵守集合的通常约定。

关于language-agnostic - 子类导致父类(super class)中的意外行为——OO 设计问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1487194/

相关文章:

c++ - C++基类在编译时未定义

java - 没有泛型的愚蠢证明迭代的API设计

c++ - "overriding"非虚拟方法的官方术语

php - 与数据库和对象交互的最佳方式

css - 如何使用自定义样式覆盖默认的 PrimeFaces CSS?

java - 理解继承和覆盖

python - 覆盖Python模块中的 "private"方法

database - 关于数据库,每个开发人员都应该了解什么?

algorithm - 是否有任何非递归/堆栈消耗,自下而上的二叉树遍历算法?

language-agnostic - 为什么要用finally?