继承会破坏封装吗?

13
假设我有一个CSV文件,并且创建了一个名为CsvFile的类,该类继承自java.io.File。这个类可以解析CSV文件并返回一些数据,比如文件中有多少列。它还可以用于需要输入java.io.File的函数,例如FileUtils.copyFile(File from, File to)。
我的同事认为我从继承方面暴露了太多内容。他的想法是通过将其保存在私有属性中来包装java.io.File,而不是继承它。他认为从文件中公开所有公共方法/属性会破坏封装性,但我认为这是一个好处,因为我们免费获得了java.io.File中的所有函数。
你怎么看?

要么这样,要么不这样,但结合两者才是正确的方式。首先继承,以免重复造轮子,然后使用封装模式使轮子发挥其作用。 - Code Droid
7个回答

15

我更倾向于支持你的同事:继承java.util.File将暴露不适用于CsvFile对象的方法,例如list()listFiles()setExecutable()等。

java.util.File作为属性放在getter后面似乎是一个更好的选择:它不会向用户公开无关操作,并允许您从所选的基类进行继承。


1
补充答案:是的,在这种情况下,继承将会破坏封装性,并泄露实现细节,即一个CVS文件是使用java.io.File实现的。 - Soronthar
1
可能并非二选一的情况。继承以自定义,然后包装以缩小您希望公开的方法范围。 - Code Droid
要么这样,要么不这样,但结合两者才是正确的方式。首先继承以避免重复发明轮子,然后使用封装模式使得轮子能够发挥其作用。 - Code Droid
但您失去了使用java.io.file作为基类的好处。使用FileUtils.copyFile(csvFile.getFile(),toFile)会很奇怪。其次,您只列出了一些可能不适用于文件的功能,但这是Java实现或操作系统的问题。我想添加的是,还有一些可以在继承中使用的函数,如getMtime(),getSize(),rename()... - Frank
谢谢您的建议。我昨晚想了一下。我认为我们的讨论可能会受到java.io.file的影响。我正在考虑这可能并不是继承概念的问题,而是java.io.File本身的问题。这个类是模糊的,并且包含一些应该属于“文件夹”或特定文件类型(如可执行文件)的功能。它只包含太多特定功能,让我们感到不堪重负。我宁愿说java.io.File不是一个好的扩展类。 - Frank
显示剩余4条评论

5

我认为这完全取决于课程的目的。如果你真的想要扩展行为,那么我认为它是有意义的。如果你不是在扩展File的行为,而只是创建一个CSV对象,那么封装会限制它的行为仅限于其意图。


1

您可能还考虑将其更通用化,以便可以接受来自各种源的CSV格式的InputStream或Reader(这些源无法(或很难)发出到文件系统)。您仍然可以为方便而拥有java.io.File setter/constructor。


1
这实际上是一个很好的辩论。你的同事在这个问题上站在了历史的正确一面。通常,继承的问题归结为is-a与has-a的关系。通常使用组合比继承更灵活。在你的情况下,这是一个棘手的问题。毕竟,csv文件是一个文件。说csv文件有一个文件甚至听起来都不对。也可以考虑做继承,但是包装继承的文件,以便只公开那些你想要的CSV文件方法。我还会研究一些设计模式,其中你想从A继承,但向世界公开更有限的接口。我几乎肯定有一个设计模式适用于此。只是记不起名字了...
“我认为不是二选一,而是两者兼顾。首先继承,以免重复造轮子,然后使用封装的模式,使轮子发挥其作用。”

0
关于你的问题:
“继承是否会破坏封装性?”
根据Joshua Bloch的《Effective Java》所述,继承总是会破坏封装性:
“与方法调用不同,继承违反了封装性[Snyder86]。换句话说,子类对其超类的实现细节依赖于其正确的功能。”
关于你应该使用继承还是组合,正如许多人已经说过的,这取决于你的CsvFile是否属于“文件”类型,即java.util.File的概念。

0
也许我的观点太自由了,但是…… 封装和继承存在的理由,就是为了程序员。(看看从汇编语言到高级语言的“进化”过程。)更高层次的抽象/范式可以编写更好的代码。当然,关键是要定义“更好”。对我来说,这是可维护性、自我文档化和代码复用性。这就是为什么在你特定的情况下,我会选择封装而不是继承。也许一开始编写需要花费更多的工作量,但是以后维护起来会轻松得多。(当然,假设这个 CSV 东西是一个更大的项目的一部分。)

0
你的同事提到的方法也有好处,它只公开你真正需要的方法,这使得你的API变得非常小 - 这样用户就清楚如何使用你的类(你可以把你的公共API看作某种文档)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接