Eliminating One-to-One Interfaces in Java

Unfortunately, it´s still common to see the practice of coupling every class with an interface, even if that means we only have one implementation. Many resources discuss this problem [1, 2, 3, 4, 5], but they fail to offer practical guidance on how to refactor it in an existing project.

This post aims to address the issue by providing a quick refactoring solution.

Single implementation interface

I repeatedly come across the following anti-pattern in Java projects:

Service service = new ServiceImpl();

Essentially, each class follows a naming convention where it is named _ServiceImpl and is the only implementation of an interface named _Service.

Although interfaces have their place, creating one that only mirrors one class is counterproductive and leads to the following problems identified by Adam Bien 13 years ago [3]:

Imagine you get another implementation (thats the whole point of an interface) - how would you name it?

If a suitable name cannot be found for an implementing class, it often indicates that the class may be overly complex or trying to do too many things, potentially violating the Single Responsibility principle.


It doubles the amount of artifacts - and significantly increases the “complexity”

Now you have the clutter of two files instead of one for everything.


The navigation in the IDE is less fluent

When you´re debugging and jump into a method call from ServiceImpl, you´re redirected to the interface signature and not the actual implementation you want. Although it may appear to be a minor inconvenience, it's important to note that as a software developer, the majority of your time is spent reading code.


For a more in-depth read on this problem, I recommended the first section of Victor Rentea´s post.

Now let´s see how we can quickly refactor this anti-pattern when it occurs frequently within a project.

Refactor Unnecessary Interfaces

  1. Press Shift twice to bring up the Search Everywhere dialog.
  2. Type run inspection by name and select the option when it appears. inspection
  3. In the Enter inspection name dialog, type interface with a single direct inheritor and select it from the list. single direct inheritor
  4. Choose the desired inspection scope, such as Project Files, Whole Project, or a custom scope.
  5. Click OK to run the inspection.
  6. This will show you a list of all the interfaces in the selected scope that have only one implementation. one-implementation
  7. We are now going to Inline an interface by double clicking on one of results, click on the interface name and press Ctrl+Alt+N (or Cmd+Option+N on macOS) to bring up the “Inline” refactoring window and press Enter. You can also right click on the interface name -> Refactor -> Inline to Anonymous Class. inline-references

With these steps all references to a single interface are removed and replaced with the class implementation. However we are still left with the Impl suffix in the class names. To get rid of this we will use the Find and Replace functionality:

  1. Press Ctrl+Shift+R (or Cmd+Option+R on macOS) to open the Replace in Path dialog. Alternatively right click on project and click Replace in Files...

  2. In the top field, enter Impl and make sure you have the Cc button enabled. Leave the bottom field empty: replace-all

  3. Finally click on Replace All.

References

  1. Martin Fowler. “InterfaceImplementationPair.” Martin Fowler’s bliki, 2014. https://martinfowler.com/bliki/InterfaceImplementationPair.html

  2. Alexsandro Souza . “Best Practices in Software Development: Interface Overuse” DZone, 2020. https://dzone.com/articles/good-practices-interface-overuse

  3. Adam Bien. “Service s = new ServiceImpl() - Why?” Adam Bien’s Weblog, 2010. https://www.adam-bien.com/roller/abien/entry/service_s_new_serviceimpl_why

  4. Anthony Steele. “Interfaces are overused” Anthony Steele’s Weblog, 2021. https://www.anthonysteele.co.uk/InterfacesAreOverused

  5. Victor Rentea. “overengineering-in-onion-hexagonal-architectures” Victor Rentea’s Weblog, 2023. https://victorrentea.ro/blog/overengineering-in-onion-hexagonal-architectures/