我刚刚在GitHub上查看了Java Hamcrest代码,注意到他们采用了一种看起来不直观且笨拙的策略,但这使我想知道是否我遗漏了什么。
我注意到在HamCrest API中有一个接口Matcher和一个抽象类BaseMatcher。 Matcher接口声明了这个方法,并有这个javadoc:
/**
* This method simply acts a friendly reminder not to implement Matcher directly and
* instead extend BaseMatcher. It's easy to ignore JavaDoc, but a bit harder to ignore
* compile errors .
*
* @see Matcher for reasons why.
* @see BaseMatcher
* @deprecated to make
*/
@Deprecated
void _dont_implement_Matcher___instead_extend_BaseMatcher_();
然后在BaseMatcher中,这个方法的实现如下:
/**
* @see Matcher#_dont_implement_Matcher___instead_extend_BaseMatcher_()
*/
@Override
@Deprecated
public final void _dont_implement_Matcher___instead_extend_BaseMatcher_() {
// See Matcher interface for an explanation of this method.
}
诚然,这样做既有效又可爱(也非常尴尬)。但是如果意图是让每个实现Matcher的类也扩展BaseMatcher,为什么还要使用接口呢?为什么不一开始就将Matcher作为抽象类,并让所有其他匹配器都扩展它呢?采用Hamcrest的方式有什么优势吗?或者这是一个糟糕实践的绝佳例子吗?编辑:一些好答案,但为了寻求更多细节,我提供了赏金。我认为向后/二进制兼容性问题是最好的答案。然而,我希望看到关于兼容性问题的更多细节,最好包括一些代码示例(最好是Java)。此外,“向后”兼容性和“二进制”兼容性之间是否存在细微差别?
进一步编辑:2014年1月7日——pigroxalot在下面提供了一个答案,链接到HamCrest作者在Reddit上的这个评论。我鼓励每个人都阅读它,如果你觉得它有帮助,请为pigroxalot的答案点赞。
甚至进一步编辑:2017年12月12日——pigroxalot的答案不知怎么被删除了。太遗憾了......那个简单的链接非常有帮助。