Should you always Code To Interfaces In Java [clos

2020-01-24 04:30发布

问题:


Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.

Closed 2 years ago.

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?

回答1:

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).

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).



回答2:

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.

2) When decoupling is important in terms of build dependencies

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

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.

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.



回答3:

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.

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.

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.

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

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



回答4:

Long story short, no. You are the creator of the application, so you have a decent idea of what could change. 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).



回答5:

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.

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.



回答6:

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 ";
}
}