re: Why Java Interfaces Are Terrible VIEW POST

FULL DISCUSSION
 

If one interface doesn't extend the other then no, you're not going to be able to treat an implementor of A as an implementor of B. That would be duck typing, which describes Go's type system but not Java's.

On the plus side, because Java is extremely strict about what goes where, you can just create dual constructors where one takes your DynamoImpl and the other takes an AmazonDynamoDB.

Don't do that, use a mock framework.

 

That would be duck typing, which describes Go's type system but not Java's.

This is why I should read more about language fundamentals. : )

And could you explain how the dual constructors would work? I tried that approach but when I added the argument as an attribute on the class, I would get an error (since the attribute was expected either one of the two interfaces).

 

Strictly speaking, you're "supposed" to buckle down and stub out miles of interface method implementations that throw NotImplementedExceptions and this is absolutely a kludge. It's also a little more involved than I'd thought at first (I've been writing primarily Node for years and my Java is rusty):

  • You need a wrapper (formally an "adapter") class which essentially forwards the AmazonDynamoDB methods you care about. Your Database class may be this wrapper already, in which case, great.
  • The wrapper class has two constructors: one accepts a DynamoImpl, the other an AmazonDynamoDB.
  • The wrapper class also has matching DynamoImpl and an AmazonDynamoDB fields. The "forwarding" methods choose whether to invoke dynamoImpl.putItem or amazonDynamoDB.putItem based on which one has been instantiated.

Overall I can't recommend actually doing this purely for the sake of having something easily testable. If you're using an IDE (which is not a bad idea with Java), it can stub out an interface implementation for you. Java is verbose; you kind of just have to live with it.

Very helpful; it's definitely a lot of work but it seems like that may be the one plausible solution.

 

I'm actually not sure if dual constructors would be the best course of action for what you're trying to do (unless I'm severely misinterpreting either of you two). I would personally either just use a mocking framework to automatically make a generic mock class that implements AmazonDynamoDB (which is similar to what you were attempting to do, OR just make a mock class yourself that implements it, and use your IDE or a lot of copy/pasting to basically implement all the methods you don't care about as stubs (i.e. "return null").

Dual constructors basically means: have a constructor that takes the real AmazonDynamoDB, and a constructor that takes the fake one. But then you have to basically implement code in the class you're testing, that reacts differently to whether you're using the real or fake one, and that kinda spits in the face of both polymorphism and mocking.

@forstmeier this is also good advice, look into mock frameworks like Mockito. I don't know if there's anything more current.

My thoughts exactly with the dual constructors when I realized I couldn't set the inputs of the constructors to the same attribute within the class; creating "test vs prod" switches raises red flags for me.

You can set them to the same attribute if they both inherit from/implement that attribute. For example, you could make your attribute an AmazonDynamoDB, and have a constructor that takes the real one, and a constructor that takes the fake one, and have them both set the same attribute to what they're given.

HOWEVER, this is more or less useless, because you could just make your constructor take an AmazonDynamoDB as well, and pass either type into that constructor.

code of conduct - report abuse