如何避免Java中脆弱的基类

时间:2013-03-10 23:41:34

标签: java inheritance polymorphism encapsulation base-class

我正在研究脆弱的基类问题,并发现以下文章很有趣:https://www.research.ibm.com/haifa/info/ple/papers/class.pdf

在本文中,有人认为如果Java有一个“密封的”访问修饰符会很棒;不像C#中的'密封',这相当于Java的'final'关键字。提出的密封机制使得不可能将这些密封类扩展到其包装之外。

然而,我发现的关于FBC问题的大部分材料可以追溯到90年代末,00年代早期,所以我想知道“问题”不再是一个主要问题。

我知道Joshua Bloch是限制性使用继承的倡导者,特别是在图书馆之间,他当然似乎是一个Java权威。

我知道如何通过创建一组从具有私有构造函数的类继承的最终内部类来实现oligomorphy,但这似乎有点不合适。

提出的密封是否基本类似于使类default / package-private,或者今天Java中是否存在某种类密封机制?

3 个答案:

答案 0 :(得分:2)

  

然而,我发现的关于FBC问题的大部分材料可以追溯到90年代末,00年代早期,所以我想知道“问题”不再是一个主要问题。

我认为这个问题现在已经得到了很好的理解。同样,你不会发现太多最近的论文讨论GOTO的问题以及如何解决它们,不是因为这些问题不再存在,而是因为人们现在知道如何避免它们。

  

[建议的类密封机制]与使类default / package-private基本相同吗?

没有。包 - 私有类和“密封”类是相似的,因为它们都不能被包外的类扩展,但它们的不同之处在于前者也不能被包外的类使用。也就是说 - 如果类X是包私有的,那么其包外的类甚至不能引用X:不extends X,没有X x = new X(),没有{ {1}}。但如果它只是密封,那么不同包中的类不能写Class<X> clazz = X.class,但仍然可以写extends XX x = new X()等等。 (同样重要的是,如果Class<X> clazz = X.class是子类,它仍然可以写X x = new Y()。所以它仍然可以利用Y的类型层次结构,即使它本身不能扩展X。)

答案 1 :(得分:0)

  

我知道如何通过创建一组从具有私有构造函数的类继承的最终内部类来实现oligomorphy,但这似乎有点不合适。

我不会说这种技术不合适 - 真正的问题是主流OOP语言缺乏按案例定义类型的机制。这样做会将案例与类型混为一谈(除非您通过将子类设为私有来隐藏子类),但它是Java中唯一的选项。

<小时/> ruakh's answer解决了有关密封机制的问题,所以我会跳过这个问题。至于避免脆弱的基类问题,this paper提出了一个目前在Java中工作的解决方案。我们的想法是制作所有公开方法final,并根据protected方法实施它们。这可以确保子类只能覆盖您认为安全的那些方法。

在主流OOP语言中实现的继承问题是,当你必须选择加入时,你必须选择退出。也就是说,除了按案例定义类型之外,我不确定继承的其他用途是什么,不能更好地替换为聚合/组合。

答案 2 :(得分:-1)

实际上没有脆弱的基类问题这样的事情,尽管它有一个Wikipedia page,甚至还有一个StackOverflow question。您找不到最近引用它的原因是因为它在80年代中期被重命名为 The Incompetent Programmer Problem

它被重命名的原因是因为有人终于意识到它所描述的问题,在基类中改变一些看似无关紧要的方法在所有继承的子类中具有深远的影响,实际上并不是oop的问题,它是将错误的代码放入基类的问题。

如果你想正确地编写oop并希望使用继承,那么你必须完全明确地确保你的基类只 包含完全稳定完全可靠代码。因为一旦你开始从中衍生出来,你就会陷入困境。如果你发现你很容易改变你的基类,一旦你从基础派生出它几次,你基本上已经开始自己的脚了。

对于奇怪的私人等级制度的解决并不是答案。