The Concise Interface Implementation Pattern

A convenient pattern to always use interfaces where possible but to keep the code-footprint and complexity of relations small

This article recaps why using abstraction is better then concrete implementation and how to minimize the burden of overhead for using it. This is aimed at Java, but is valid in many statically typed languages which support OOP and the concept of contracts and inner classes.

Interfaces are great. They expose a clear API, enhance encapsulation and make clean polymorphism possible. Interfaces encourage you to think about responsibility and therefore the required methods and their signature, as well as nearly invite you to properly document them. Interfaces create the basic blocks of abstraction for a clean architecture.

Now in daily life it can get annoying to use interfaces everywhere. Especially in those instances were you are sure there will only be one implementation or usage in the foreseeable future. In which package should the interface and implementation go? What would be appropriate names? Is the overhead really worth it considering the interface will not be exposed to other modules? For these instance I use the following pattern:

The Concise Interface Implementation

Use this pattern if

  • …you keep the interface module-private and do not plan the expose it as an API; ie. it is implementation detail of the module
  • …expect only a single implementation (apart from creating mocks during testing)
  • …it is ok that interface and implementation have the same visibility

The goal is to keep the implementation concise, that means the interface and default implementation can be at the exact same location creating a kind of “mini” module. The implementation doesn’t even need it’s own unique name.

The template looks like this (Java 7+):

public interface MyInterface {    void interfaceMethod1();

void interfaceMethod2();
final class Default implements MyInterface{ @Override
public void interfaceMethod1() {
//impl
}
@Override
public void interfaceMethod2() {
//impl
}
}
}

You would define your interface, like any other. Then you add a inner final static (implied) class called Default representing your default implementation. Static inner classes do not have any reference to their outer class, so it behaves just like a normal class defined as top-level class.

And you would use it like this:

MyInterface m = new MyInterface.Default();

As you can see, the intend and usage is very clear: you instantiate the default implementation of MyInterface.

I believe seeing such a construct also conveys the exact properties described above: single implementation and module private; so developers can treat it accordingly.

Future-proof

If in any point in time you wish to have multiple implementation or expose this interface as an API you just move the Default implementation to it’s own class and give it a proper name (IntelliJ can do this for you). The interface and implementation are not tied to each other, they are just defined in the same location in the source code.

Avoid unnecessary Naming

Naming is hard. With this concept we avoid having to invent a synthetic name for the default implementation of a simple interface. Oftentimes if developers get the naming wrong, it can get very confusing and hard to read, like this example:

TextTransformer t = new StringManager();

Avoid Codebase Clutter

No need to create new packages structures that do not match the intended one. No need to search for the implementation (although IDEs like IntelliJ make it very easy).

Testable

One of the main benefits of using interfaces is the better testability. By using well-defining contracts mocking becomes easy. You can use either a mocking library like Mockito or you just implement the interface in your test package. Either way you are able to exactly test the behavior you are interested in and mock the rest.

Conclusion

By abstracting and creating contracts with interfaces we can create better software. Unfortunately in some cases using interfaces can be unnecessary overhead. The proposed concise interface implementation pattern mitigates this issue by defining the name and location of the implementation without removing the flexibility of later using multiple implementations or as an standalone API.

--

--

--

Software Engineer currently working through the stack: JS frontend, Android Mobile, Java Backend. Security is my passion.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Patrick Favre-Bulle

Patrick Favre-Bulle

Software Engineer currently working through the stack: JS frontend, Android Mobile, Java Backend. Security is my passion.

More from Medium

Visitor Design Pattern in Java

Java vs .Net: Which Technology Is Better For Software Development?

JUnit5: Parallelization of Parameterized Tests (Only)

JUnit5 Parallelization Configurations

How To Manage Multi JAVA Versions On Mac