Java 只有一个实现的接口
在使用jmock时,如果设置类冒名顶替器,则可以模拟具体的类。我注意到类冒名顶替器在遗留包中,所以我真的不想使用它(特别是因为使用IDE中的重构工具提取接口非常容易)。我也不喜欢有具体类的实例变量 但是,在提取接口时,我注意到代码库中出现了一种模式。很多时候,一个接口只有一个实现具体类。我更喜欢尽可能地使用接口,但拥有所有这些额外文件似乎真的很冗长。此外,每次我想向类添加新方法时,更新接口和更新实现者都有点繁琐Java 只有一个实现的接口,java,oop,interface,Java,Oop,Interface,在使用jmock时,如果设置类冒名顶替器,则可以模拟具体的类。我注意到类冒名顶替器在遗留包中,所以我真的不想使用它(特别是因为使用IDE中的重构工具提取接口非常容易)。我也不喜欢有具体类的实例变量 但是,在提取接口时,我注意到代码库中出现了一种模式。很多时候,一个接口只有一个实现具体类。我更喜欢尽可能地使用接口,但拥有所有这些额外文件似乎真的很冗长。此外,每次我想向类添加新方法时,更新接口和更新实现者都有点繁琐 这仅仅是你为适当的抽象所付出的代价,还是有一种更好的方法我没有想到?即使接口中只有g
这仅仅是你为适当的抽象所付出的代价,还是有一种更好的方法我没有想到?即使接口中只有getter/setter,所有类都应该实现一个接口吗?如果接口冗长乏味,无论理论上有什么优势,都是不好的风格 如果使用您的工具很容易提取接口,为什么现在就这么做?为什么不在它真正有目的的时候去做呢。我看到太多的代码是为了未来而设计的,而不是为了解决眼前的问题
当然,所有关于这些问题的辩论都只是意见。没有事实可供发现。如果接口只是getter和setter,那么听起来它更多地与数据有关,而不是与行为有关,而且听起来不像是我要嘲笑的那种东西。我很乐意在其他类的测试中直接使用简单的生产代码。我只为提供服务的类注入依赖项 我感觉到你的痛苦,但就我个人而言,我仍然编写接口,即使目前只有一个生产实现。很多时候,我会发现在模拟一段时间后,我也编写了存根或伪实现。除非您真的对测试调用者和服务之间的交互感兴趣,否则赝品最终可能会变得更易于使用(导致更清晰的测试)
这还意味着,当有人想要查看某个特定依赖项提供的方法时,他们可以只查看接口,而不涉及任何实现。如果有额外的接口会冒犯您,您可以(手动)创建模拟对象,作为所模拟类的子类 如果一个类仅仅由(简单的)getter和setter组成,那么嘲笑它几乎没有任何意义。使用真实的东西。你提到“适当的抽象”。嗯,只有当接口对多个类有意义时才合适。特别是考虑到您是从具体的类中提取接口,您可能最终在接口中得到了不应该存在的方法。当然,如果接口本身首先存在是有意义的话 我要指出的最后一点是,您的接口似乎不是特别稳定。您似乎在暗示向接口添加方法对您来说是司空见惯的。当类的契约(即其接口)如此易变时,我会质疑类的抽象
总而言之,我不认为立即为所有内容提供接口就构成了适当的抽象。相反,从设计的角度来看,先等待类的公共接口稳定下来,然后考虑适当的抽象(即不只是点击IDE中的
“提取接口…”
按钮)要好得多。另外,一个类可能会抽象成几个不相关的接口,而不是单个接口。如果您的接口主要是属性,那么所有实现类都可能是相关的,也许抽象类更适合您的需要。然后你就可以避免一些陈词滥调了。抽象类的主要功能仍然可以通过接口进一步抽象
interface IRunner {
void run();
int doOtherThing();
}
abstract class Thing implements IRunner {
//this is class-specific
abstract void run();
//this is common to all 'Things'
int doOtherThing() { return 0; }
//as are these properties
public int getProp() {...}
public void setProp(int val) {...}
}
public class Goo extends Thing {
public void run() {
int i = getProp() + doOtherThing();
makeMagicGoo(i);
}
}
有一个关键用例,即使您只编写了一个对象的实现,为对象生成接口也是至关重要的:您希望能够为类的实例生成JDK代理(例如,如果您正在执行Spring AOP,这很有用)。可以使用cglib之类的工具为任意对象构建代理,但要复杂得多;相比之下,JDK代理很简单
我也有点担心你的IDE并没有给你带来应有的帮助。我发现使用我的(Eclipse),只要在实现中用
@Override
标记方法并选择正确的自动修复选项,就可以在接口中创建方法。(这并不是说它会选择正确的方法解释,但这是你的工作。)我所说的一些一般要点:
- 测试中的模拟是替代实现。因此,即使产品代码中只有一个实现,代码库中也会有多个实现
- 比起getter和setter,更喜欢构造函数注入。这也将使不可变对象更自然
- 接口描述了一个行为的契约,并且以一种接口的用户不需要知道实现细节的方式进行描述
- 不要为与这些事情无关的事情制作接口:抽象掉实现细节;多个替代实现;可模仿性;行为
- 与很少有大型互联部件的设计相比,更喜欢具有许多小型组成部件的设计
- 如果某个东西很难测试或模拟,那么尝试将其分解为具有更简单API的较小部分,然后组合这些部分
- 给事物精确的名称,不仅要注意代码的重复,还要注意结构和名称的重复
- 避免实现继承-更喜欢组合。接口继承很难被误用,而且经常会失效