使用安全做法吗默认方法是穷人版本的特质在 Java 8 中?
有人声称这可能会让熊猫感到悲伤如果你只是为了使用它们,因为它很酷,但这不是我的意图。人们还经常提醒,引入默认方法是为了支持 API 演化和向后兼容性,这是事实,但这并不意味着将它们用作特征本身是错误或扭曲的。
I have 以下实际用例心里:
public interface Loggable {
default Logger logger() {
return LoggerFactory.getLogger(this.getClass());
}
}
或者也许,定义一个PeriodTrait
:
public interface PeriodeTrait {
Date getStartDate();
Date getEndDate();
default isValid(Date atDate) {
...
}
}
诚然,可以使用组合(甚至辅助类),但它看起来更冗长和混乱,并且不允许从多态性中受益。
So, 使用默认方法作为基本特征是否可以/安全,或者我应该担心不可预见的副作用吗?
几个问题on SO 与 Java 与 Scala 特征相关;这不是重点。我也不只是征求意见。相反,我正在寻找权威的答案或至少是现场洞察力:如果您使用默认方法作为公司项目的特征,它是否会成为定时炸弹?
简短的回答是:如果您安全地使用它们,那就安全了:)
尖刻的回答:告诉我什么you是指特征,也许我会给你一个更好的答案:)
严肃地说,“特质”这个词并没有明确的定义。许多 Java 开发人员最熟悉的是在 Scala 中表达的特征,但无论从名称上还是实际上来看,Scala 都不是第一种拥有特征的语言。
例如,在 Scala 中,特征是有状态的(可以有var
变量);在《堡垒》中,它们是纯粹的行为。 Java 的带有默认方法的接口是无状态的;这是否意味着它们不是特质? (提示:这是一个棘手的问题。)
同样,在 Scala 中,特征是通过线性化组合而成的;如果上课A
延伸特质X
and Y
,然后按顺序X
and Y
混合在一起决定了之间如何发生冲突X
and Y
已解决。在 Java 中,不存在这种线性化机制(它被拒绝,部分原因是它太“不像 Java”。)
向接口添加默认方法的直接原因是为了支持界面演变,但我们很清楚我们正在超越这个范围。无论您认为这是“界面进化++”还是“特征--”,都是个人解释的问题。因此,要回答您有关安全的问题……只要您坚持该机制实际支持的内容,而不是试图将其扩展到它不支持的内容,就应该没问题。
一个关键的设计目标是,从client对于接口来说,默认方法应该与“常规”接口方法没有区别。因此,方法的默认性仅对designer and 实施者界面的。
以下是一些完全符合设计目标的用例:
界面演变。在这里,我们向现有接口添加一个新方法,该接口根据该接口上的现有方法有一个合理的默认实现。一个例子是添加forEach
方法Collection
,其中默认实现是根据以下形式编写的iterator()
方法。
“可选”方法。在这里,接口的设计者是说“如果实现者愿意接受所带来的功能限制,则不需要实现此方法”。例如,Iterator.remove
被给予默认值,抛出UnsupportedOperationException
;因为绝大多数的实现Iterator
无论如何都有这种行为,默认情况下该方法本质上是可选的。 (如果行为来自AbstractCollection
被表示为默认值Collection
,我们可以对变异方法做同样的事情。)
方便的方法。这些方法纯粹是为了方便起见,通常也是通过类的非默认方法来实现的。这logger()
第一个示例中的方法是对此的合理说明。
组合器。这些是基于当前实例实例化接口的新实例的组合方法。例如,方法Predicate.and()
or Comparator.thenComparing()
是组合器的例子。
如果您提供默认实现,您还应该为默认提供一些规范(在 JDK 中,我们使用@implSpec
javadoc 标签)以帮助实现者了解他们是否想要重写该方法。一些默认值,例如便捷方法和组合器,几乎永远不会被覆盖;其他的,比如可选方法,经常被覆盖。您需要提供关于默认承诺执行的操作的足够规范(而不仅仅是文档),以便实现者可以就是否需要覆盖它做出明智的决定。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)