Why Java interfaces aren't terrible (just strict)
Tags: java, coding
Published: 2018-11-02 19:01:24

A [recent article](https://dev.to/forstmeier/why-java-interfaces-are-terrible-1abp) described some problems when dealing with Java interfaces, coming from a language that allows duck typing.

The bottom line is this. There is an interface:
``` java
public interface DynamoImpl {
  public PutItemResult putItem(PutItemRequest putItemRequest);

  public GetItemResult getItem(GetItemRequest getItemRequest);
}
```

And there is a class `AmazonDynamoDB`. That class has the two above methods, but also a lot more. Now John, the programmer, wants to expose only these two methods of `AmazonDynamoDB` to the rest of his program. He wants to use them in his class `Database`:

``` java
public class Database {
    public DynamoImpl db;

    // code removed for simplicity

    public Database(DynamoImpl db) {
        this.db = db;
    }
}
```

Now: in a language that supports duck typing, you could just pass an instance of class `AmazonDynamoDB` to the constructor, and call the two methods (because the class has them). Not in Java, though. You need to pass in an instance of a class that *literally* `implements` the `DynamoImpl` interface (or extends a class that does so). But `AmazonDynamoDB` does not implement that interface.

The easiest way to achieve the same goal in Java is to create a wrapper that delegates to an `AmazonDynamoDB` instance:
``` java
public class AmazonDynamoDbWrapper implements DynamoImpl{

	private AmazonDynamoDB amazonDynamoDB;

	public AmazonDynamoDbWrapper(AmazonDynamoDB amazonDynamoDB) {
		this.amazonDynamoDB = amazonDynamoDB;
	}
	
	@Override
	public PutItemResult putItem(PutItemRequest putItemRequest) {
		return amazonDynamoDB.putItem(putItemRequest);
	}

	@Override
	public GetItemResult getItem(GetItemRequest getItemRequest) {
		return amazonDynamoDB.getItem(getItemRequest);
	}

}
```
Yes, a bit verbose, but pretty straight forward once you understand the pattern. Now you can pass an instance of this class to an instance of `Database`. 

So much for the production code. What about tests?

The easiest solution is to provide a minimal implementation of the `DynamoImpl` interface, like so:

``` java
public class StubbedDynamoImpl implements DynamoImpl {

	@Override
	public PutItemResult putItem(PutItemRequest putItemRequest) {
		return new PutItemResult(/* Test data here */);
	}

	@Override
	public GetItemResult getItem(GetItemRequest getItemRequest) {
		return new GetItemResult(/* Test data here */);
	}
}
```

Again, you can pass an instance of this class to the `Database` instance's constructor, in a test:
``` java
public class DatabaseTest {

	@Test
	public void createsDatabase() {
		Database database = new Database(new StubbedDynamoImpl());
		// Whatever your test assertions are, here
	}
	// ...
}
```
No need for fancy mocking frameworks if all you want to expose is two methods.
This is the easiest solution I could think of. I hope it's useful.

P.S.
One word concerning Java conventions: please don't use the suffix Impl for interfaces. This should be used for concrete implementation classes (if at all), or otherwise you might confuse a lot of people.