Java interfaces - What exactly is in the contract? [closed]
Asked Answered
A

3

8

I know and understand the value of interfaces in Java. You code to the interface, and then you can change your implementations without having to change any code using the interface. Often the term "contract" is used in connection with interfaces. The way I understand it is the interface defines the "contract" between the application and the implementation.

So, when I create an implementation, I have to fulfill the contract. My questions is, what exactly is in that contract that I have to fulfill?

Obviously, at a minimum you have to provide methods with the same signatures as the interface. The code won't compile otherwise. Is that all the "contract" entails? It seems like there should be more.

For example, I've read articles debating the value of testing to the interface vs. testing specific implementations, or doing both. I see great value in having tests for an interface so that you know what inputs have what expected outputs. It would seem to me that this would also be part of the interface "contract". Every implementation of the interface should produce the same outputs from the same inputs. Obviously there's no way to enforce this contract in the code, but it can be enforced through test cases. Am I wrong in my thinking here?

Finally, what about side effects that implementations have? Here, I'm mainly talking about any persistence that might happen as part of the implementation. Say I have an implementation that is saving some records to the DB while it preforms the operation. Would this somehow be part of the interface "contract"? If so, how could you enforce this contract? From the interface level, I have no idea what the implementation is actually doing. All I know is I give it inputs, and it gives me an output, which I can test. Is any persistence that happens also considered an "output"? If so, I just don't see how this can be tested and enforced. I'm a proponent of persistence ignorance, so I could know that something should be persisted, but I don't know how it is persisted. So, I just don't how to tell when something actually persisted. It may be simple if your interface has some simple CRUD operations, but I want to think about more complicated interfaces.

I hope my question makes sense and that someone can provide some good feedback. I want to discuss this generally, but I can provide a specific example if it's not clear what I'm talking about.

Airlia answered 30/3, 2012 at 18:4 Comment(4)
To test the 'contract', write unit tests for the interface, which every implementation has to call first (there's ways to do this). If there's implementation-specific pieces that need to be checked, that comes next. Generally speaking, you want all tests to be as side-effect-less as possible. Thus, when testing persistence stuff, you generally use mock objects in place of (Actually) persisted objects; from the calling piece of code, it is a persisted object - it just never ended up in a database.Sulfaguanidine
en.wikipedia.org/wiki/Design_by_contract look for "the contract for each method will normally contain the following pieces of information..." Doesn't apply strictly to Java, but yeah...Lanai
documentation. That's what specifies a lot of the extra information about the contract of a given interface. Note: "Every implementation of the interface should produce the same outputs from the same inputs." wouldn't be true for an interface IBook and a GetPage(1) call if each implementation represented a different book...Sher
@X-Zero I understand the value of mock objects, and I am using one. My point is that in my interface test, all I have is the interface. I use Spring to configure it for me, but in the test itself, it doesn't know how it was configured. So, how would I make sure something persisted (even if it's persisted in a mock object), when it has no idea how it's configured to persist data.Airlia
D
5

I think "contract" and "Interface" have very less in common.

An interface is something like a door. A door may pass typical human, but not elephants, giraffes or car.

An contract is when you could assure that through the door only female, or male, or software developer will come.

So a contract defines BEHAVIOR while interface defines which information is passed

Danika answered 30/3, 2012 at 18:11 Comment(1)
OK, that's a good clarification. I guess my question to that would be, how do enforce behavior? Is that only possible when testing specific implementations? Or can you enforce interface "behavior"?Airlia
C
2

I think you're making too big a deal about the term "contract".

"Eiffel" has a very specific "design by contract" philosophy. Personally, I think other languages would benefit from something similar.

Informally, you can certainly think of Java's "interfaces" as being a "contract". Your definition of a Java interface is certainly good:

at a minimum you have to provide methods with the same signatures as the interface. The code won't compile otherwise.

Q: Is that all the "contract" entails?

A: Probably not. It all depends on how you define "contract" ;)

But, IMHO, Java interfaces are a much cleaner feature than the horror of C++ "multiple inheritance". And one of the primary motivations behind both are to support "mixins":

Similarly, Java intefaces also provide a clean, relatively simple, type-save solution to support "callbacks".

Final suggestion: please consider the difference between "interface" and "abstract class". This might also give you additional insight into Java Interfaces, and how you can use them effectively in your own code:

Interface vs Abstract Class (general OO)

Craft answered 30/3, 2012 at 18:9 Comment(2)
How do Java interfaces realize the concept of mixins, seeing that they don't provide implementation?Shockproof
I guess this post stems from trying to write test cases for my interface. At the very highest level my question could be something like what should interface tests actually test? Only return values based on arguments passed in? Maybe changes to objects that were passed in? Should there be any part of the test that makes sure certain behavior is implemented?Airlia
S
0

So a contract is the method signature + any documentation associated with the function / class . A takeaway from this is that an interface does not mean the same thing as the java keyword interface . An interface is anything that allows you to interact with another system. So to the question of how do you fulfill the contract of a function declared as so:

    /**  Throws IllegalArgumentException if s is null.    
Converts the input <b>s</b> into an {@link Integer}  */
    function go(String s);

You would need to write an implementation as follows:

function go(String s)  
{  
    if(null == s) throw new IllegalArgumentException();  
    int i = Integer.parseInt(s);
}  

Contrived yes, but this should explain how to implement a contract and abide by it.

Sabotage answered 30/3, 2012 at 18:12 Comment(1)
In this simple case, it's easy to test and make sure the contract is met. In the cases of persistence, it seems like it would be more difficult. Does this also mean that you would document what persistence needs to happen?Airlia

© 2022 - 2024 — McMap. All rights reserved.