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:
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?
It doubles the amount of artifacts - and significantly increases the “complexity”
The navigation in the IDE is less fluent
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
- Press Shift twice to bring up the
Search Everywhere
dialog. - Type
run inspection by name
and select the option when it appears. - In the
Enter inspection name
dialog, typeinterface with a single direct inheritor
and select it from the list. - Choose the desired inspection scope, such as
Project Files
,Whole Project
, or a custom scope. - Click
OK
to run the inspection. - This will show you a list of all the interfaces in the selected scope that have only one implementation.
- 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
(orCmd+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.
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:
-
Press
Ctrl+Shift+R
(orCmd+Option+R on macOS
) to open the Replace in Path dialog. Alternatively right click on project and clickReplace in Files...
-
In the top field, enter
Impl
and make sure you have theCc
button enabled. Leave the bottom field empty: -
Finally click on
Replace All
.
References
-
Martin Fowler. “InterfaceImplementationPair.” Martin Fowler’s bliki, 2014. https://martinfowler.com/bliki/InterfaceImplementationPair.html
-
Alexsandro Souza . “Best Practices in Software Development: Interface Overuse” DZone, 2020. https://dzone.com/articles/good-practices-interface-overuse
-
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
-
Anthony Steele. “Interfaces are overused” Anthony Steele’s Weblog, 2021. https://www.anthonysteele.co.uk/InterfacesAreOverused
-
Victor Rentea. “overengineering-in-onion-hexagonal-architectures” Victor Rentea’s Weblog, 2023. https://victorrentea.ro/blog/overengineering-in-onion-hexagonal-architectures/