Java Interface Naming Conventions [closed]

2019-03-09 09:22发布

问题:

I work on a Java web-app that uses Spring for dependency injection and JMock for mocking out these dependencies in our unit tests.

Currently our team is at a point were we have a few different opinions in terms of how to name certain interfaces that we use. We have no issue with naming the interfaces in our domain that have multiple implementations, that is simple. However, when it comes to interfaces for which we only have one implementation and intend on only having one implementation in the future, we have hit a snag.

The reason that we have such interfaces is purely for mocking, for example, we have services and repositories that we mock out in our unit tests and these services will be named "DocumentMappingService" or for repositories "EmployeeRepository". At the moment some of the guys just prefix the associated interface name with an "I", i.e. "IDocumentMappingService" and "IEmployeeRepository". Others name the interface as I have above and then append an "Impl" after the interface name for the implementing class.

The third "faction" feels that both of these options are poor. Looking at literature such as the well-known "Growing object-oriented software, guided by tests" would lead one to believe that both of the before-mentioned options are poor and that the interface name should clearly define the contract and the implementing classes name should clearly specify how that contract has been implemented. We have found this quite difficult to do in the case I have mentioned above though.

I was hoping that someone out there has had a similar issue before and has some suggestions ito which option is the best and why. Also, if you think that the "I" and "Impl" options are both poor, then please suggest a specific alternative convention.

回答1:

There's no "one" correct answer here. Naming is quite subjective but what matters the most is that it should be consistent throughout the code base. I would just like to add (to @fge's answer) some more options for you:

  • Making the Interfaces more generic.

    EmployeeRepository implements Repository
    DocumentMappingService implements MappingService
    
  • Calling your single implementations "defaults".

    DefaultEmployeeRepository implements EmployeeRepository
    DefaultDocumentMappingService implements DocumentMappingService
    
  • Calling your base implementations (if, sometimes extended) as "support".

    EmployeeRepositorySupport implements EmployeeRepository
    DocumentMappingServiceSupport implements DocumentMappingService
    

I come across these naming conventions a lot when using the Spring Framework.


Edit : In response to user nyxz's comment about the -Base or Base- convention.

Like I said before, naming is subjective and there's nothing wrong with using the Base nomenclature as such. But, personally, I don't prefer using it. Here's why:

  1. If your implementations would mostly be used directly, then the code instantiating the classes leaves an impression of breaking the OOP hierarchy. That perhaps a specific derived class should have been instantiated.

  2. If your implementations would mostly be extended from, then the word Base becomes redundant in a way. You're extending from it so, of course, it's a base class. Duh!

The 2nd point mostly applies to peripheral classes in your project. Extension points that you provide when you're publishing a framework or library to be used and extended in other projects.

On the other hand, a good use case for using the Base terminology would be for classes internal to your framework that factor common functionality out of other peripheral classes. Since, these classes aren't supposed to be instantiated directly, they are marked abstract, which is in line with the 1st point.

Here's the Adapter hierarchy from the Android framework as an example:

  • Interface hierarchy.

    public interface Adapter
    public interface ListAdapter extends Adapter
    public interface SpinnerAdapter extends Adapter
    
  • The abstract Base class that factors out the common behaviour and interface implementations.

    public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter
    
  • Peripheral classes that are mostly instantiated but sometimes extended by an Android application.

    public class SimpleAdapter extends BaseAdapter implements Filterable
    public class ArrayAdapter<T> extends BaseAdapter implements Filterable
    


回答2:

An answer to such a question can only reflect the tastes of the person who answers... So these are my tastes:

  • I hate the initial I. It brings nothing of value to the picture. It reminds me of the Hungarian notation where float variables were to be suffixed with _f or the like. No.
  • The Impl suffix is good enough. But on the other hand, it sounds weird.

I'd suggest two alternate proposals for a given interface Foo:

  • create a single implementation but not with the Impl suffix; find a more "appealing" name. For instance, TheOnlyOneFoo;
  • create a factory with an appended s: Foos. Then, a Foo instance would be a Foos.newInstance(whatever, args).

I prefer the second solution, for two reasons:

  • it can hide the fact that the real implementation has an ugly name;
  • it can be extended easily when you realize one day that "no, after all, there is more than one implementation for that": just add another static factory method; and if the only existing method in existence sounds too generic, you can just mark it as @Deprecated.

It could even be used in a manner so that all Foo implementations are package local, or even private to the factory. But stack traces would look worse...

No real solution there ;)

edit: as for mocking:

  • I'd recommend mockito. Really. It is very easy to use, and very powerful.
  • If those are "one-implementation classes" you are dealing with, maybe there is a better alternative in the JDK itself? What is it that you want to do exactly? The JDK has hidden treasures...

And as a final note... Have you considered the builder pattern?