Java 与内部实现的接口-好或坏

Java 与内部实现的接口-好或坏,java,interface,coding-style,Java,Interface,Coding Style,我正在做一个有很多someInterface-someInterfaceImpl对的项目。几天前,我有了一个想法(可能是受阅读一些目标c代码的启发),将默认实现作为一个内部类包含进来。 现在,一些同事(都比我有更多的java经验)看到了这个想法——反馈既震惊又惊讶(“这是可行的?”) 我在谷歌上搜索了一下,但没有找到太多证据证明这种“模式”(我个人喜欢): 和 您怎么看?尤其是在“默认”实现与接口紧密耦合的情况下 更新 我刚刚发现: (请参阅接受的答案)接口的全部要点是将用户与实现分离(默认或

我正在做一个有很多someInterface-someInterfaceImpl对的项目。几天前,我有了一个想法(可能是受阅读一些目标c代码的启发),将默认实现作为一个内部类包含进来。 现在,一些同事(都比我有更多的java经验)看到了这个想法——反馈既震惊又惊讶(“这是可行的?”)

我在谷歌上搜索了一下,但没有找到太多证据证明这种“模式”(我个人喜欢): 和

您怎么看?尤其是在“默认”实现与接口紧密耦合的情况下

更新 我刚刚发现:


(请参阅接受的答案)

接口的全部要点是将用户与实现分离(默认或非默认)。通过将实现作为内部类包含,可以克服这一问题。实际上,您没有保存任何代码行,API也变得杂乱无章。最终,您不得不对接口的用户隐藏内部类,比如将其设置为私有或默认范围,这可能是最好避免的。另外,如果您的默认实现需要更改,但您已将接口作为API的一部分发布,该怎么办。这是一个坏主意,因为它没有很多好处,是一种反模式

最后,如果您真的有一个默认实现,那么它可能应该是一个基类(而不是一个接口),而其他实现则扩展该类并重写行为

我认为这篇文章对一个类似的问题进行了有趣的讨论:

我同意上述答案,但在某些情况下,包括实施是合乎逻辑的,例如:

  • 您正在编写匿名函数(当您的接口只有一个方法,并且您正在像函数语言中的匿名函数一样使用它时),这是正常的,但是很少

如果您的默认实现非常琐碎,并且很可能保持这种状态,并且如果没有任何东西扩展它或很可能扩展它,那么这可能就是最好的选择。你不想把它放在自己的文件里,你还会把它放在哪里?我建议使用公共实例将类设置为私有(假设没有状态):

我不认为这会对执行造成任何影响(类实例中没有数据),但您会得到更好的Javadoc。您可以使用匿名类并保存一行代码

您甚至可能需要一些其他“默认”实例。对于类似集合的接口,您可能有一个具有单个默认条目的接口,或者具有相同默认条目的无穷多个(
hasNext
始终返回
true

我认为关键是默认实现不能依赖于接口之外的任何东西。不要使用外部类和接口,除非它们在接口的主体中被引用,也不要使用扩展默认值的外部类。这个接口变得比标准的接口概念稍微多了一点,但仍然是独立的


另一个关键点是,您不希望在一个.java文件中包含太多的代码,但也不希望包含太少的代码。

如果默认实现需要更改,那么您可以删除一个包含新实现的版本,而不需要更改接口定义本身。如果要用作默认实现,也不需要隐藏该实现。我不认为按照OP描述的方式来做有什么好处,但我也不认为你提出的负面影响是非常可怕的——我只是觉得把它们放在一起,强制一个新的接口发行版来进行实现更改是没有意义的。我正要补充一个关于基本实现vs抽象vs接口的答案,你打败了我:-)太可怕了,也许不是。糟糕,是的。它打破了接口是未实现API的整个概念。如果没有其他内容,它会使接口的源代码可读性降低,因为它与默认实现混杂在一起,而默认实现应该对接口的用户隐藏。您是对的,但在我的特殊情况下,创建接口的唯一原因是测试能力(gwt with mvp模式)。因此,api永远不会被“发布”,而且很可能除了mock之外,再也不会有其他实现。除此之外,有人读过我提供的链接吗?似乎还有其他好处?!上面的Radio 2不是具有默认实现的接口定义,而是具有被覆盖的默认实现的
抽象类的扩展。请注意,由于提供了默认实现,因此它是作为
抽象类
而不是
接口
完成的。
ModifyListener
接口没有默认实现。您已经创建了一个实现接口的匿名内部类,这就是我要说的。问题是关于内部类,他没有说明它是否是匿名的。这是一个要点:-)-但我不是在谈论匿名类。我说的是“combo.addModifyListener(new ModifyListener.Impl())”啊。我又读了一遍这个问题。不知怎的,我错过了最后一句话,谢谢你指出。
/** An interface a lot like java.util.Collection. */
public interface WhatEver  {
    private class Default  implements Whatever  {
        // Methods...
    }
    /** A default implementation that is always empty.  Suitable as a NULL value. */
    public final WhatEver  DEFAULT = new Default();
    // Rest of interface...