Overview id-mask bkdf singlestep-kdf bcrypt slf4j-timber armadillo bytes-java hkdf dice under-the-hood uber-apk-signer uber-adb-tools indoor-positioning density-converter Dali BlurTestAndroid
A convenient pattern to always use interfaces where possible but to keep the code-footprint and complexity of relations small
Java, Interfaces, Patterns, Dependency Injection, Testing
The Concise Interface Implementation Pattern
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:
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+):
1public interface MyInterface {
2
3 void interfaceMethod1();
4
5 void interfaceMethod2();
6
7 final class Default implements MyInterface{
8
9 @Override
10 public void interfaceMethod1() {
11 //impl
12 }
13
14 @Override
15 public void interfaceMethod2() {
16 //impl
17 }
18
19 }
20}
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:
1MyInterface 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.
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.
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:
1TextTransformer t = new StringManager();
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).
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.
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.
This article was published on 4/11/2018 on medium.com.
Overview How to Centralize your Checkstyle Configuration with Maven A Better Way to Protect Your IDs Security Best Practices: Symmetric Encryption with AES in Java and Android: Part 2: AES-CBC + HMAC The Bcrypt Protocol… is kind of a mess The Concise Interface Implementation Pattern Improving ProGuard Name Obfuscation Handling Proguard as Library Developer Managing Logging in a Multi-Module Android App Security Best Practices: Symmetric Encryption with AES in Java and Android
Patrick Favre-Bulle 2020