你应该总是用 Java 编写接口代码吗

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3194278/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 00:45:26  来源:igfitidea点击:

Should you always Code To Interfaces In Java

javainterfaceoop

提问by Tarski

I understand the principles of Coding to Interfaces - to decouple the implementation from the interface, and to allow implementations of the interface to be swapped in and out.

我了解编码到接口的原则 - 将实现与接口分离,并允许接口的实现交换进出。

Should I code to interfaces for every class I write or is that overkill? I don't want to double the number of source files in a project unless it's really worth it.

我应该为我编写的每个类编写接口代码还是过度杀伤?我不想让项目中的源文件数量翻倍,除非它真的值得。

What factors can I use to decide whether to code by interface or not?

我可以使用哪些因素来决定是否按接口编码?

采纳答案by Sandor Murakozi

In general I agree with the other answers: use an interface when you know or anticipate change and/or different implementation, or go for testability.

总的来说,我同意其他答案:当您知道或预期更改和/或不同的实现时使用接口,或者进行可测试性。

But it's not always easy to know in advance what may change in the future, especially if you are not so experienced. I think the solution for that problem is refactoring: keep it simple (= no interface) as long as it is not needed. When the need arises simply do an "Introduce/Extract interface" refactoring (supported by almost all decent IDEs).

但是,提前知道未来可能会发生什么变化并不总是那么容易,尤其是如果您没有那么有经验的话。我认为该问题的解决方案是重构:只要不需要,就保持简单(= 没有接口)。当需要时,只需进行“引入/提取接口”重构(几乎所有像样的 IDE 都支持)。

When you do it extract only those methods that are actually needed by the callers. Don't be afraid to extract more then one separate interfaces (if not all of the extracted methods are really coherent).

当你这样做时,它只提取调用者实际需要的那些方法。不要害怕提取多个单独的接口(如果不是所有提取的方法都非常一致)。

One driver of the refactoring might be the testing: if you can't easily test something with classes only consider introducing one/some interface(s). This will also allow you to use mocking which may greatly simplify testing in many cases.

重构的一个驱动因素可能是测试:如果您不能轻松地用类测试某些东西,请只考虑引入一个/一些接口。这也将允许您使用模拟,这可以在许多情况下大大简化测试。

Edit:based on Tarski's comment I've realized one more important scenario/adjustment to the previous statements:
If you provide an external API (for other [sub]projects, or really release it "to the wild") then using interfaces in the API (except for simple value classes) is almost always a good idea.
It will allow you to change the impl if you like without disturbing the client code. You will have a problem only if you also have to change the interface. Not breaking compatibility will be very tricky (if not impossible).

编辑:基于 Tarski 的评论,我意识到了一个更重要的场景/对先前陈述的调整:
如果您提供外部 API(用于其他 [子] 项目,或真正将其“发布到野外”),则在API(除了简单的值类)几乎总是一个好主意。
如果您愿意,它将允许您在不干扰客户端代码的情况下更改 impl。仅当您还必须更改接口时,您才会遇到问题。不破坏兼容性将非常棘手(如果不是不可能的话)。

回答by Eyal Schneider

I use it when at least one of the following is true:

当至少满足以下一项时,我会使用它:

1) I want to decouple unrelated modules/classes from each other, and I want it to be reflected by the java package dependencies.

1)我想将不相关的模块/类彼此解耦,并且我希望它通过java包依赖项来反映。

2) When decoupling is important in terms of build dependencies

2) 当解耦在构建依赖项方面很重要时

3) When the implementation may change through configuration or dynamically at runtime (usually due to some design pattern)

3)当实现可能通过配置或在运行时动态改变时(通常是由于某种设计模式)

4) When I want a class to be testable, I make its "link points" to external resources interfaces, so that I can use mock implementations.

4) 当我想要一个类是可测试的时,我将它的“链接点”设置为外部资源接口,以便我可以使用模拟实现。

5) Less common: When I want to have an option to restrict the access to some class. In this case my method returns an interface instead of the actual class, so the caller knows that I don't expect him to do other operations on the returned value.

5)不太常见:当我想有一个选项来限制对某个类的访问时。在这种情况下,我的方法返回一个接口而不是实际的类,所以调用者知道我不希望他对返回的值进行其他操作。

回答by duffymo

No, every class should not have an interface. It's overkill squared.

不,每个类都不应该有一个接口。这是矫枉过正的平方。

You use an interface when you need to abstract what's done from how it's done, and you're certain that the implementation can change.

当您需要从完成的方式中抽象出已完成的内容时,您可以使用接口,并且您确定实现可以更改。

Have a look at the java.util Collections API for a good example. The List interface is a nice abstraction for the general idea of a List, but you can see that there are many ways to implement it: ArrayList, LinkedList, etc.

查看 java.util Collections API 的一个很好的例子。List 接口是对 List 的一般思想的一个很好的抽象,但你可以看到有很多方法可以实现它:ArrayList、LinkedList 等。

UPDATE: So what about that case where you design a concrete class, decide after you have clients that an interface is needed, and then you break your clients by adding an interface? Yup, that's what happens. How can you know what you don't know? No software or methodology can fix that.

更新:那么如果你设计一个具体的类,在你有客户之后决定需要一个接口,然后你通过添加一个接口来破坏你的客户呢?是的,就是这样。你怎么知道你不知道的?没有任何软件或方法可以解决这个问题。

The good news for you is that extracting an interface from a concrete class is an easy refactoring to do for both you and your clients. IDEs handle that kind of thing routinely. You and your clients should take advantage of them.

对您来说好消息是,从具体类中提取接口对于您和您的客户来说都是一种简单的重构。IDE 经常处理这种事情。您和您的客户应该利用它们。

I'd say that layers, like services and persistence, should always have interfaces. Anything that can be proxied should have an interface. If you're doing Spring AOP, anything that you want to decorate with an aspect should have an interface.

我会说层,如服务和持久性,应该总是有接口。任何可以代理的东西都应该有一个接口。如果你在做 Spring AOP,任何你想用方面装饰的东西都应该有一个接口。

Model or value objects, like Person or Address or Phone, should not have an interface. An immutable value object should not have an interface.

模型或值对象,如 Person 或 Address 或 Phone,不应有接口。不可变值对象不应该有接口。

The rest fall into gray areas. Use your best judgement.

其余的则属于灰色地带。使用你最好的判断。

回答by Awaken

Long story short, no. You are the creator of the application, so you have a decent idea of what couldchange. Some of the design pattern books go a little crazy on it in my opinion since they seem to always push designing to interfaces and not implementation no matter what. Sometimes, it is just overkill. For my latest application (small size), I have a database interface because I think there is a chance I may later port it to the web and switch to MySQL. Of course in reality, it would be easy to create a database interface down the road from my existing class and just add "implements myDbInterface" later with a couple of small changes. This works because I am the only developer though. On a larger team, or different type of product, it may be a different answer. Just use your best judgement (after reading all the good SO answers of course).

长话短说,不。您是应用程序的创建者,因此您很清楚可以做什么改变。在我看来,一些设计模式书籍对此有点疯狂,因为无论如何它们似乎总是将设计推向接口而不是实现。有时,这只是矫枉过正。对于我最新的应用程序(小尺寸),我有一个数据库接口,因为我认为以后有机会将它移植到 Web 并切换到 MySQL。当然,在现实中,很容易从我现有的类中创建一个数据库接口,然后通过一些小的更改添加“实现 myDbInterface”。这是有效的,因为我是唯一的开发人员。在更大的团队或不同类型的产品中,可能会有不同的答案。只需使用您的最佳判断(当然,在阅读完所有好的 SO 答案之后)。

回答by mP.

I like to think of that one uses interfaces when pluggability and the potential for different behaviour is important. Services are the perfect fit. One might want a default implementation, but faking(mocking) etc is another. This obviously means there should be an intf as there will always be at least 2 forms.

我喜欢认为当可插拔性和不同行为的潜力很重要时使用接口。服务是完美的契合。人们可能想要一个默认的实现,但伪造(模拟)等是另一个。这显然意味着应该有一个 intf ,因为总是至少有 2 种形式。

Value types on the other hand should be final classes. They should never be extended. Value types include something like Suburb, MimeType. If there are variations of these use composition. As a goal i try and put little behaviour if any in my value types. Validating the simple type it wraps etc is probably the most complex thing that it does. Eg A Color class which takes r/g/b should validate that each component is between 0 and 255 and thats it.

另一方面,值类型应该是最终类。它们永远不应该被延长。值类型包括诸如 Suburb、MimeType 之类的东西。如果这些使用组合有变化。作为一个目标,我尝试在我的值类型中加入很少的行为。验证它包装的简单类型等可能是它所做的最复杂的事情。例如,采用 r/g/b 的 Color 类应该验证每个组件都在 0 到 255 之间,仅此而已。

回答by Nirbhay Mishra

Yes use interface when you expect a behavior to change. . In future.

是的,当您希望行为改变时使用接口。. 在未来。

Or your class which can handle changes in clear way.

或者你的班级可以清晰地处理变化。

eg.

例如。

public static void main(String s[])
{
 Employee e1=new Employee(new Salesman());
 Employee e2=new Employee(new Manager());

 system.out.println(e1.performaction());
 system.out.println(e1.performaction());
}

Class Employee
{

//which changes frequently
Authority a;

public Employee(Authority a)
{
this.a=a;
}    
public String performAction()
{
a.action();
}
}

//------------------------------------------------------------------

//------------------------------------------------ ------------------

interface Authority
{ 
public String action();
}

class Manager implements Authority 
{ 
public String action()
{
 returns "I manages People";
}

 class SalesMan implements Authority 
{
  public String action() 
{
 returns "I Sell things Company makes ";
}
}