Uly*_*ahi 9 java inheritance composition java-8 default-method
通常承认,通过继承扩展接口的实现不是最佳实践,并且该组合(例如,从头开始再次实现接口)更加可维护.
这是有效的,因为接口契约迫使用户实现所有所需的功能.但是在java 8中,默认方法提供了一些可以"手动"覆盖的默认行为.请考虑以下示例:我想设计一个用户数据库,该数据库必须具有List的功能.出于效率目的,我选择通过ArrayList来支持它.
public class UserDatabase extends ArrayList<User>{}
Run Code Online (Sandbox Code Playgroud)
这通常不被认为是一种很好的做法,如果真的希望列表的全部功能并遵循通常的"遗产构成"的座右铭,我宁愿这样做:
public class UserDatabase implements List<User>{
//implementation here, using an ArrayList type field, or decorator pattern, etc.
}
Run Code Online (Sandbox Code Playgroud)
但是,如果不注意,则不需要覆盖某些方法,例如spliterator(),因为它们是List接口的默认方法.问题是,List的spliterator()方法执行得比ArrayList的spliterator()方法差得多,后者已针对ArrayList的特定结构进行了优化.
这迫使开发者
所以问题是:在这种情况下,人们应该更喜欢构成而不是继承吗?
在开始考虑性能之前,我们总是应该考虑正确性,即在您的问题中我们应该考虑使用继承而不是委托所暗示的内容.这个EclipseLink/JPA问题已经说明了这一点.由于继承,如果尚未填充延迟填充列表,则排序(同样适用于流操作)不起作用.
因此,我们必须在专业化,覆盖新default方法,在继承情况下完全中断的可能性以及default方法不能在委托情况下以最大性能工作的可能性之间进行权衡.我认为,答案应该是显而易见的.
既然你的问题是关于新default方法是否会改变这种情况,那么应该强调的是,与以前甚至不存在的东西相比,你所说的是性能下降.让我们留下这个sort例子吧.如果您使用授权和不覆盖default排序方法,该default方法可能比优化的性能较低的ArrayList.sort方法,但Java 8之前,后者并不存在,不优化的算法ArrayList是标准的行为.
因此,您不会在Java 8下使用委派失去性能,当您不覆盖该方法时,您只是没有获得更多default.我认为,由于其他改进,性能仍然优于Java 7(没有default方法).
由于StreamAPI在Java 8之前不存在,因此API不易比较.但是,很明显,类似的操作,例如,如果您手动实现减少,除了通过Iterator您的委托列表之外别无选择.防止remove()尝试,因此包装ArrayList Iterator,或使用size()和get(int)代表支持List.因此,没有预先default方法API可以表现出比defaultJava 8 API 更好的性能的情况,因为ArrayList过去无论如何都没有特定的优化.
也就是说,通过以不同的方式使用组合可以改进您的API设计:完全不让UserDatabase工具List<User>.只需提供Listvia访问方法即可.然后,其他代码不会尝试流式传输UserDatabase实例,而是覆盖访问器方法返回的列表.返回的列表可以是只读包装器,它提供JRE本身提供的最佳性能,并注意default在可行的情况下覆盖方法.