Related
Given the following class:
class Example implements Interface1, Interface2 {
...
}
When I instantiate the class using Interface1:
Interface1 example = new Example();
...then I can call only the Interface1 methods, and not the Interface2 methods, unless I cast:
((Interface2) example).someInterface2Method();
Of course, to make this runtime safe, I should also wrap this with an instanceof check:
if (example instanceof Interface2) {
((Interface2) example).someInterface2Method();
}
I'm aware that I could have a wrapper interface that extends both interfaces, but then I could end up with multiple interfaces to cater for all the possible permutations of interfaces that can be implemented by the same class. The Interfaces in question do not naturally extend one another so inheritance also seems wrong.
Does the instanceof/cast approach break LSP as I am interrogating the runtime instance to determine its implementations?
Whichever implementation I use seems to have some side-effect either in bad design or usage.
I'm aware that I could have a wrapper interface that extends both
interfaces, but then I could end up with multiple interfaces to cater
for all the possible permutations of interfaces that can be
implemented by the same class
I suspect that if you're finding that lots of your classes implement different combinations of interfaces then either: your concrete classes are doing too much; or (less likely) your interfaces are too small and too specialised, to the point of being useless individually.
If you have good reason for some code to require something that is both a Interface1 and a Interface2 then absolutely go ahead and make a combined version that extends both. If you struggle to think of an appropriate name for this (no, not FooAndBar) then that's an indicator that your design is wrong.
Absolutely do not rely on casting anything. It should only be used as a last resort and usually only for very specific problems (e.g. serialization).
My favourite and most-used design pattern is the decorator pattern. As such most of my classes will only ever implement one interface (except for more generic interfaces such as Comparable). I would say that if your classes are frequently/always implementing more than one interface then that's a code smell.
If you're instantiating the object and using it within the same scope then you should just be writing
Example example = new Example();
Just so it's clear (I'm not sure if this is what you were suggesting), under no circumstances should you ever be writing anything like this:
Interface1 example = new Example();
if (example instanceof Interface2) {
((Interface2) example).someInterface2Method();
}
Your class can implement multiple interfaces fine, and it is not breaking any OOP principles. On the contrary, it is following the interface segregation principle.
It is confusing why would you have a situation where something of type Interface1 is expected to provide someInterface2Method(). That is where your design is wrong.
Think about it in a slightly different way: Imagine you have another method, void method1(Interface1 interface1). It can't expect interface1 to also be an instance of Interface2. If it was the case, the type of the argument should have been different. The example you have shown is precisely this, having a variable of type Interface1 but expecting it to also be of type Interface2.
If you want to be able to call both methods, you should have the type of your variable example set to Example. That way you avoid the instanceof and type casting altogether.
If your two interfaces Interface1 and Interface2 are not that loosely coupled, and you will often need to call methods from both, maybe separating the interfaces wasn't such a good idea, or maybe you want to have another interface which extends both.
In general (although not always), instanceof checks and type casts often indicate some OO design flaw. Sometimes the design would fit for the rest of the program, but you would have a small case where it is simpler to type cast rather than refactor everything. But if possible you should always strive to avoid it at first, as part of your design.
You have two different options (I bet there are a lot more).
The first is to create your own interface which extends the other two:
interface Interface3 extends Interface1, Interface2 {}
And then use that throughout your code:
public void doSomething(Interface3 interface3){
...
}
The other way (and in my opinion the better one) is to use generics per method:
public <T extends Interface1 & Interface2> void doSomething(T t){
...
}
The latter option is in fact less restricted than the former, because the generic type T gets dynamically inferred and thus leads to less coupling (a class doesn't have to implement a specific grouping interface, like the first example).
The core issue
Slightly tweaking your example so I can address the core issue:
public void DoTheThing(Interface1 example)
{
if (example instanceof Interface2)
{
((Interface2) example).someInterface2Method();
}
}
So you defined the method DoTheThing(Interface1 example). This is basically saying "to do the thing, I need an Interface1 object".
But then, in your method body, it appears that you actually need an Interface2 object. Then why didn't you ask for one in your method parameters? Quite obviously, you should've been asking for an Interface2
What you're doing here is assuming that whatever Interface1 object you get will also be an Interface2 object. This is not something you can rely on. You might have some classes which implement both interfaces, but you might as well have some classes which only implement one and not the other.
There is no inherent requirement whereby Interface1 and Interface2 need to both be implemented on the same object. You can't know (nor rely on the assumption) that this is the case.
Unless you define the inherent requirement and apply it.
interface InterfaceBoth extends Interface1, Interface2 {}
public void DoTheThing(InterfaceBoth example)
{
example.someInterface2Method();
}
In this case, you've required InterfaceBoth object to both implement Interface1 and Interface2. So whenever you ask for an InterfaceBoth object, you can be sure to get an object which implements both Interface1 and Interface2, and thus you can use methods from either interface without even needing to cast or check the type.
You (and the compiler) know that this method will always be available, and there's no chance of this not working.
Note: You could've used Example instead of creating the InterfaceBoth interface, but then you would only be able to use objects of type Example and not any other class which would implement both interfaces. I assume you're interested in handling any class which implements both interfaces, not just Example.
Deconstructing the issue further.
Look at this code:
ICarrot myObject = new Superman();
If you assume this code compiles, what can you tell me about the Superman class? That it clearly implements the ICarrot interface. That is all you can tell me. You have no idea whether Superman implements the IShovel interface or not.
So if I try to do this:
myObject.SomeMethodThatIsFromSupermanButNotFromICarrot();
or this:
myObject.SomeMethodThatIsFromIShovelButNotFromICarrot();
Should you be surprised if I told you this code compiles? You should, because this code doesn't compile.
You may say "but I know that it's a Superman object which has this method!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman variable.
You may say "but I know that it's a Superman object which implements the IShovel interface!". But then you'd be forgetting that you only told the compiler it was an ICarrot variable, not a Superman or IShovel variable.
Knowing this, let's look back at your code.
Interface1 example = new Example();
All you've said is that you have an Interface1 variable.
if (example instanceof Interface2) {
((Interface2) example).someInterface2Method();
}
It makes no sense for you to assume that this Interface1 object also happens to implement a second unrelated interface. Even if this code works on a technical level, it is a sign of bad design, the developer is expecting some inherent correlation between two interfaces without actually having created this correlation.
You may say "but I know I'm putting an Example object in, the compiler should know that too!" but you'd be missing the point that if this were a method parameter, you would have no way of knowing what the callers of your method are sending.
public void DoTheThing(Interface1 example)
{
if (example instanceof Interface2)
{
((Interface2) example).someInterface2Method();
}
}
When other callers call this method, the compiler is only going to stop them if the passed object does not implement Interface1. The compiler is not going to stop someone from passing an object of a class which implements Interface1 but does not implement Interface2.
Your example does not break LSP, but it seems to break SRP. If you encounter such case where you need to cast an object to its 2nd interface, the method that contains such code can be considered busy.
Implementing 2 (or more) interfaces in a class is fine. In deciding which interface to use as its data type depends entirely on the context of the code that will use it.
Casting is fine, especially when changing context.
class Payment implements Expirable, Limited {
/* ... */
}
class PaymentProcessor {
// Using payment here because i'm working with payments.
public void process(Payment payment) {
boolean expired = expirationChecker.check(payment);
boolean pastLimit = limitChecker.check(payment);
if (!expired && !pastLimit) {
acceptPayment(payment);
}
}
}
class ExpirationChecker {
// This the `Expirable` world, so i'm using Expirable here
public boolean check(Expirable expirable) {
// code
}
}
class LimitChecker {
// This class is about checking limits, thats why im using `Limited` here
public boolean check(Limited limited) {
// code
}
}
Usually, many, client-specific interfaces are fine, and somewhat part of the Interface segregation principle (the "I" in SOLID). Some more specific points, on a technical level, have already been mentioned in other answers.
Particularly that you can go too far with this segregation, by having a class like
class Person implements FirstNameProvider, LastNameProvider, AgeProvider ... {
#Override String getFirstName() {...}
#Override String getLastName() {...}
#Override int getAge() {...}
...
}
Or, conversely, that you have an implementing class that is too powerful, as in
class Application implements DatabaseReader, DataProcessor, UserInteraction, Visualizer {
...
}
I think that the main point in the Interface Segregation Principle is that the interfaces should be client-specific. They should basically "summarize" the functions that are required by a certain client, for a certain task.
To put it that way: The issue is to strike the right balance between the extremes that I sketched above. When I'm trying to figure out interfaces and their relationships (mutually, and in terms of the classes that implement them), I always try to take a step back and ask myself, in an intentionally naïve way: Who is going to receive what, and what is he going to do with it?
Regarding your example: When all your clients always need the functionality of Interface1 and Interface2 at the same time, then you should consider either defining an
interface Combined extends Interface1, Interface2 { }
or not have different interfaces in the first place. On the other hand, when the functionalities are completely distinct and unrelated and never used together, then you should wonder why the single class is implementing them at the same time.
At this point, one could refer to another principle, namely Composition over inheritance. Although it is not classically related to implementing multiple interfaces, composition can also be favorable in this case. For example, you could change your class to not implement the interfaces directly, but only provide instances that implement them:
class Example {
Interface1 getInterface1() { ... }
Interface2 getInterface2() { ... }
}
It looks a bit odd in this Example (sic!), but depending on the complexity of the implementation of Interface1 and Interface2, it can really make sense to keep them separated.
Edited in response to the comment:
The intention here is not to pass the concrete class Example to methods that need both interfaces. A case where this could make sense is rather when a class combines the functionalities of both interfaces, but does not do so by directly implementing them at the same time. It's hard to make up an example that does not look too contrived, but something like this might bring the idea across:
interface DatabaseReader { String read(); }
interface DatabaseWriter { void write(String s); }
class Database {
DatabaseConnection connection = create();
DatabaseReader reader = createReader(connection);
DatabaseReader writer = createWriter(connection);
DatabaseReader getReader() { return reader; }
DatabaseReader getWriter() { return writer; }
}
The client will still rely on the interfaces. Methods like
void create(DatabaseWriter writer) { ... }
void read (DatabaseReader reader) { ... }
void update(DatabaseReader reader, DatabaseWriter writer) { ... }
could then be called with
create(database.getWriter());
read (database.getReader());
update(database.getReader(), database.getWriter());
respectively.
With the help of various posts and comments on this page, a solution has been produced, which I feel is correct for my scenario.
The following shows the iterative changes to the solution to meet SOLID principles.
Requirement
To produce the response for a web service, key + object pairs are added to a response object. There are lots of different key + object pairs that need to be added, each of which may have unique processing required to transform the data from the source to the format required in the response.
From this it is clear that whilst the different key / value pairs may have different processing requirements to transform the source data to the target response object, they all have a common goal of adding an object to the response object.
Therefore, the following interface was produced in solution iteration 1:
Solution Iteration 1
ResponseObjectProvider<T, S> {
void addObject(T targetObject, S sourceObject, String targetKey);
}
Any developer that needs to add an object to the response can now do so using an existing implementation that matches their requirement, or add a new implementation given a new scenario
This is great as we have a common interface which acts as a contract for this common practise of adding response objects
However, one scenario requires that the target object should be taken from the source object given a particular key, "identifier".
There are options here, the first is to add an implementation of the existing interface as follows:
public class GetIdentifierResponseObjectProvider<T extends Map, S extends Map> implements ResponseObjectProvider<T, S> {
public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
targetObject.put(targetKey, sourceObject.get("identifier"));
}
}
This works, however this scenario could be required for other source object keys ("startDate", "endDate" etc...) so this implementation should be made more generic to allow for reuse in this scenario.
Additionally, other implementations may require more context information to perform the addObject operation... So a new generic type should be added to cater for this
Solution Iteration 2
ResponseObjectProvider<T, S, U> {
void addObject(T targetObject, S sourceObject, String targetKey);
void setParams(U params);
U getParams();
}
This interface caters for both usage scenarios; the implementations that require additional params to perform the addObject operation and the implementations that do not
However, considering the latter of the usage scenarios, the implementations that do not require additional parameters will break the SOLID Interface Segregation Principle as these implementations will override getParams and setParams methods but not implement them. e.g:
public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S, U> {
public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
targetObject.put(targetKey, sourceObject.get(U));
}
public void setParams(U params) {
//unimplemented method
}
U getParams() {
//unimplemented method
}
}
Solution Iteration 3
To fix the Interface Segregation issue, the getParams and setParams interface methods were moved into a new Interface:
public interface ParametersProvider<T> {
void setParams(T params);
T getParams();
}
The implementations that require parameters can now implement the ParametersProvider interface:
public class GetObjectBySourceKeyResponseObjectProvider<T extends Map, S extends Map, U extends String> implements ResponseObjectProvider<T, S>, ParametersProvider<U>
private String params;
public void setParams(U params) {
this.params = params;
}
public U getParams() {
return this.params;
}
public void addObject(final T targetObject, final S sourceObject, final String targetKey) {
targetObject.put(targetKey, sourceObject.get(params));
}
}
This solves the Interface Segregation issue but causes two more issues... If the calling client wants to program to an interface, i.e:
ResponseObjectProvider responseObjectProvider = new GetObjectBySourceKeyResponseObjectProvider<>();
Then the addObject method will be available to the instance, but NOT the getParams and setParams methods of the ParametersProvider interface... To call these a cast is required, and to be safe an instanceof check should also be performed:
if(responseObjectProvider instanceof ParametersProvider) {
((ParametersProvider)responseObjectProvider).setParams("identifier");
}
Not only is this undesirable it also breaks the Liskov Substitution Principle - "if S is a subtype of T, then objects of type T in a program may be replaced with objects of type S without altering any of the desirable properties of that program"
i.e. if we replaced an implementation of ResponseObjectProvider that also implements ParametersProvider, with an implementation that does not implement ParametersProvider then this could alter the some of the desirable properties of the program... Additionally, the client needs to be aware of which implementation is in use to call the correct methods
An additional problem is the usage for calling clients. If the calling client wanted to use an instance that implements both interfaces to perform addObject multiple times, the setParams method would need to be called before addObject... This could cause avoidable bugs if care is not taken when calling.
Solution Iteration 4 - Final Solution
The interfaces produced from Solution Iteration 3 solve all of the currently known usage requirements, with some flexibility provided by generics for implementation using different types. However, this solution breaks the Liskov Substitution Principle and has a non-obvious usage of setParams for the calling client
The solution is to have two separate interfaces, ParameterisedResponseObjectProvider and ResponseObjectProvider.
This allows the client to program to an interface, and would select the appropriate interface depending on whether the objects being added to the response require additional parameters or not
The new interface was first implemented as an extension of ResponseObjectProvider:
public interface ParameterisedResponseObjectProvider<T,S,U> extends ResponseObjectProvider<T, S> {
void setParams(U params);
U getParams();
}
However, this still had the usage issue, where the calling client would first need to call setParams before calling addObject and also make the code less readable.
So the final solution has two separate interfaces defined as follows:
public interface ResponseObjectProvider<T, S> {
void addObject(T targetObject, S sourceObject, String targetKey);
}
public interface ParameterisedResponseObjectProvider<T,S,U> {
void addObject(T targetObject, S sourceObject, String targetKey, U params);
}
This solution solves the breaches of Interface Segregation and Liskov Substitution principles and also improves the usage for calling clients and improves the readability of the code.
It does mean that the client needs to be aware of the different interfaces, but since the contracts are different this seems to be a justified decision especially when considering all the issues that the solution has avoided.
The problem you describe often comes about through over-zealous application of the Interface Segregation Principle, encouraged by languages' inability to specify that members of one interface should, by default, be chained to static methods which could implement sensible behaviors.
Consider, for example, a basic sequence/enumeration interface and the following behaviors:
Produce an enumerator which can read out the objects if no other iterator has yet been created.
Produce an enumerator which can read out the objects even if another iterator has already been created and used.
Report how many items are in the sequence
Report the value of the Nth item in the sequence
Copy a range of items from the object into an array of that type.
Yield a reference to an immutable object that can accommodate the above operations efficiently with contents that are guaranteed never to change.
I would suggest that such abilities should be part of the basic sequence/enumeration interface, along with a method/property to indicate which of the above operations are meaningfully supported. Some kinds of single-shot on-demand enumerators (e.g. an infinite truly-random sequence generator) might not be able to support any of those functions, but segregating such functions into separate interfaces will make it much harder to produce efficient wrappers for many kinds of operations.
One could produce a wrapper class that would accommodate all of the above operations, though not necessarily efficiently, on any finite sequence which supports the first ability. If, however, the class is being used to wrap an object that already supports some of those abilities (e.g. access the Nth item), having the wrapper use the underlying behaviors could be much more efficient than having it do everything via the second function above (e.g. creating a new enumerator, and using that to iteratively read and ignore items from the sequence until the desired one is reached).
Having all objects that produce any kind of sequence support an interface that includes all of the above, along with an indication of what abilities are supported, would be cleaner than trying to have different interfaces for different subsets of abilities, and requiring that wrapper classes make explicit provision for any combinations they want to expose to their clients.
If you want to use sort() method from Arrays class you MUST implement Comparable interface. This is a really good idea - you can't sort objects if they're not compatible. So you can't sort if you can't compare it's references. In this case interface is used like compatibility checker.
The question is - how can I make:
a class with a method (may do something with 2 objects)
interface that checks if this 2 objects are comatible (have compatible references)
add to my class "must use this interface" rule, so you can't use this class method without implementing specific interface, just like Comparable class does ?
Example:
public class Employee implements Comparable<Employee> {
//fields
//setters, getters
// this method must be implemented to use Arrays.sort()
public int compareTo(Employee other) {
return Double.compare(salary, other.salary);
}
}
An interface can't check anything.
You can write this:
interface One { }
interface Two { }
SomeType someMethod(One one, Two two) { ... }
The compiler will not allow anybody's code to call someMethod(a, b) unless it can prove that a is an instance of some class that implements One and b is an instance of some class that implements Two.
Is that what you're asking?
Added Info:
Arrays.sort(Object[] a) is different: The compiler does not know whether the elements in the array implement the Comparable interface or not. That information is not available until run-time.
I don't know how java.util.Arrays.sort() does it, but you you want to do the same thing in your own code, you can write this:
interface One { }
interface Two { }
SomeType someMethod(Object oneAsObject, Object twoAsObject) {
One one = One.class.cast(oneAsObject);
Two two = Two.class.cast(twoAsObject);
...
}
This is different from my first example because the compiler will let you pass in any type of object, but the function will throw a ClassCastException at run time if the wrong type of object is passed.
But why would you want to wait until run time to find an error that you could have found at compile time? (e.g., why wait until the lander is descending toward the Martian surface to find a fatal flaw that you could have found before it was launched?)
Responding to your comment:
Yes, what I mean is: if you wan't to use sort() you must implement comparable. So the question is - can I determine, that you must use some X interface if you want to use my X method.
You could do this with an abstract class.
public interface MyInterface {
public void methodA();
}
public abstract class MyAbstractClass implements MyInterface {
public void methodB(
System.out.println("Pop");
)
}
Anything that wants to use methodB must extend MyAbstractClass, and therefore must implement MyInterface.
so i was trying to understand the interfaces, but i almost only see articles that explains "how" to use the interface, my problem is to understand the "why" :
so it's better to use Interface than creating and subclassing a class, which might be useless,
so we implement the interface methods in the class, but i don't understand why this is a good thing,
Let's say :
a class like Car.java defines all the code to make the car
we create the interface Working.java with several methods like start(), stop(), etc.
we implement the methods in Diesel_Car.java, Electric_Car.java, etc.
so what does it change for Car.java? This might not be the best example, as it seems that Car should be the parent of Diesel_Car.java etc,
but what was the meaning to implement the methods in those classes?
Is there a method in Car.java that somehow "calls" the Diesel_Car.java class and its interface methods?
I've read that the interface is like a "Contract", but i only see the second part of this contract (where the method is implemented) and i'm having some trouble to imagine where the first part happen?
Thanks for your help
Lets take your example of a Base class of Car with Electric_Car and Diesel_Car Subclasses, and expand the model a bit.
Car may have the following Interfaces
Working : with start() & stop() methods
Moving : with move(), turn() & stop() methods
The Car might contain an instance of class AirConditioner which should also implement the interface Working.
The Driver object can interact with objects than implement Working , the driver can start() or stop() . (The driver can start or stop the car and the A/C seperatly).
also, since the Driver can walk around on his own (and does not always need a car) he should implement the interface Moving.
The object Ground can now interact with anything that implements Moving : either car or driver.
(Very) contrived example (non-generic, error handling removed, etc. for clarity).
List theList = new ArrayList();
theList is a List, in this case implemented by an ArrayList. Let's say we pass this to a third-party API that somewhere in its bowels adds something to the list.
public void frobList(List list) {
list.add(new Whatever());
}
Now let's say for some reason we want to do something unusual to items that are added to the list. We can't change the third-party API. We can, however, create a new list type.
public FrobbableList extends ArrayList {
public boolean add(E e) {
super.add(Frobnicator.frob(e));
}
}
Now in our code we change the list we instantiate and call the API as before:
List theList = new FrobbableList();
frobber.frobList(theList);
If the third-party API had taken an ArrayList (the actual type) instead of a List (the interface), we'd be unable to do this as easily. By not locking the API in to a specific implementation, it provided us the opportunity to create custom behavior.
Taken further, this is a concept fundamental to extensible, debuggable, testable code. Things like dependency injection/Inversion of Control rely on coding to interfaces to function.
I am making another attempt to explain the concept of interface as a contract.
A typical usage scenario is when you'd like to sort a List of elements using java.util.Collections : <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T> ts)
what does this signature mean? the sort() method will accept a java.util.List<T> of objects of type T, where T is an object that implements the interface Comparable.
so, If you would like to use Collections.sort() with a list of your objects you will need them to implement the Comparable interface:
public interface Comparable<T> {
int compareTo(T t);
}
So, if you implement a class of type Car and want to compare cars by their weight using Collections.sort(), you will have to implement the Comparable interface/contract in class car.
public class Car implements Comparable<Car> {
private int weight;
//..other class implementation stuff
#Override
public int compareTo(Car otherCar) {
if (this.weight == otherCar.weight) return 0;
else if (this.weight > otherCar.weight) return 1;
else return -1;
}
}
under the hood the Collections.sort() will call your implementation of compareTo when it sorts the list.
The contract is a concept of how classes work with each other. The idea is that a interfacing class defines the methods return type and name, but doesn't provide the idea of how it is implemented. That is done by the implementing class.
The concept is that when a Interface A defines methods A and B, any class implementing that interface MUST implement A and B along with its own methods. So it might work like this:
interface InterfaceA {
void methodA();
void methodB(String s);
}
public class ClassA implements InterfaceA {
public void methodA() {
System.out.println("MethodA");
}
public void methodB(String s) {
System.out.println(s);
}
}
The contract principle is that anything implementing a interface must implement the whole interface. Anything that doesn't do this must be abstract.
Hope this helps.
Design by contract (DbC), also known as programming by contract and design-by-contract programming, is an approach for designing computer software. It prescribes that software designers should define formal, precise and verifiable interface specifications for software components, which extend the ordinary definition of abstract data types with preconditions, postconditions and invariants. These specifications are referred to as "contracts", in accordance with a conceptual metaphor with the conditions and obligations of business contracts. Wikipedia
Short-cut.
If you follow the good practice of coding against interfaces, you know that the interface defines the contract all implementation classes must adhere to.
We designed Contract Java, an extension of Java in which method contracts are specified in interfaces. We identified three design goals.
First, Contract Java programs without contracts and programs with
fully-satisfied contracts should behave as if they were run without
contracts in Java.
Second, programs compiled with a conventional Java compiler must be able to interoperate with programs
compiled under Contract Java.
Finally, unless a class declares that it meets a particular contract, it must never be blamed for failing to meet that
contract. Abstractly, if the method m of an object with type t is called, the caller should only be blamed for the
pre-condition contracts associated with t and m should only be blamed for post-condition contracts associated
with t.
These design goals raise several interesting questions and demand decisions that balance language design with
software engineering concerns. This section describes each of the major design issues, the alternatives, our decisions,
our rationale, and the ramifications of the decisions. The decisions are not orthogonal; some of the later decisions
depend on earlier ones.
Contracts in Contract Java are decorations of methods signatures in interfaces. Each method declaration may come
with a pre-condition expression and a post-condition expression; both expressions must evaluate to booleans. The
pre-condition specifies what must be true when the method is called. If it fails, the context of the method call is to
blame for not using the method in a proper context. The post-condition expression specifies what must be true when
the method returns. If it fails, the method itself is to blame for not establishing the promised conditions.
Contract Java does not restrict the contract expressions. Still, good programming discipline dictates that the expressions
should not contribute to the result of the program. In particular, the expressions should not have any side-effects.
Both the pre- and post-condition expressions are parameterized over the arguments of the method and the pseudovariable
this. The latter is bound to the current object. Additionally, the post-condition of the contract may refer to the
name of the method, which is bound to the result of the method call.
Contracts are enforced based on the type-context of the method call. If an object’s type is an interface type, the
method call must meet all of the contracts in the interface. For instance, if an object implements the interface I, a call
to one of I’s methods must check that pre-condition and the post-condition specified in I. If the object’s type is a class
type, the object has no contractual obligations. Since a programmer can always create an interface for any class, we
leave objects with class types unchecked for efficiency reasons.
For an example, consider the interface RootFloat:
interface RootFloat {
float getValue ();
float sqRoot ();
#pre { this.getValue() >= 0f }
#post { Math.abs(sqRoot * sqRoot - this.getValue()) < 0.01f }
}
It describes the interface for a float wrapper class that provides a sqRoot method. The first method, getValue, has no
contracts. It accepts no arguments and returns the unwrapped float. The sqRoot method also accepts no arguments,
but has a contract. The pre-condition asserts that the unwrapped value is greater than or equal to zero. The result type
of sqRoot is float. The post-condition states that the square of the result must be within 0.01 of the value of the float.
Even though the contract language is sufficiently strong to specify the complete behavior in some cases, such as the
previous example, total or even partial correctness is not our goal in designing these contracts. Typically, the contracts
cannot express the full behavior of a method. In fact, there is a tension between the amount of information revealed in
the interface and the amount of validation the contracts can satisfy.
For an example, consider this stack interface:
interface Stack {
void push (int i);
int pop ();
}
With only push and pop operations available in the interface, it is impossible to specify that, after a push, the top
element in the stack is the element that was just pushed. But, if we augment the interface with a top operation that
reveals the topmost item on the stack (without removing it), then we can specify that push adds items to the top of the
stack:
interface Stack {
void push (int x);
#post { x = this.top() }
int pop ();
int top ();
}
In summary, we do not restrict the language of contracts. This makes the contract language as flexible as possible;
contract expression evaluation may even contribute to the final result of a computation. Despite the flexibility of the
contract language, not all desirable contracts are expressible. Some contracts are inexpressible because they may
involve checking undecidable properties, while others are inexpressible because the interface does not permit enough
observations.
I’m currently facing a design problem and would appreciate advice on how I could resolve it:
The problem
I will use an example to illustrate my problem note this is just an example:
Suppose you have an interface called Pass with methods listed:
public interface Pass {
public boolean hasPassedA();
public boolean hasPassedB();
public boolean hasPassedC();
}
Suppose you have a class which implement this interface called Assessor:
public class Assessor implements Pass{
// how should I implement this class ??
}
Finally Student class:
public class Student {
// some code that defines student behaviour not important.
}
The question is then how can I make the interaction between the Assessor and the student object a lot more flexible?
What I noticed is that an Assessor object should be something that is abstract because in reality there is no such thing as an Assessor, but instead you have different types of assessors such as a Math Assessor or English Assessor etc, which in turn will allow me to create different types of Assessor objects e.g.
MathAssessor extends Assessor
EnglishAssessor extends Assessor
The concept is that a Student can pass if all the methods declared in the Pass interface return true and all additional methods in the subjectAssessor classes return true.
What do I do in the Assessor class? I have read about adapter design patterns but haven’t fully grasped that notion or does it even apply to this situation?
To start, the Pass interface you have is not very flexible, which could make for difficulties. For example, what if one implementation of Pass only needs to have hasPassedA, or you have an implementation which needs hasPassedA, hasPassedB, hasPassedC and hasPassedD. Then the various types of assessors will need to figure out which pass conditions to check.
A more flexible way to do this might be to do something like this. Rather than having a Pass interface, maybe something like a Condition interface (the names of the classes/interfaces should be changed to make sense for your domain).
public interface Condition {
// true means the condition passed, false means it did not
boolean evalutate();
}
Now you could have a single Assessor class (I'm not sure if this is exactly how your assessor would work, but it's just a guideline):
public class Assessor {
boolean assess(Collection<Condition> conditions) {
for (Condition c : conditions) {
if (!c.evaluate()) {
return false;
}
}
// all conditions passed
return true;
}
}
Hopefully this helps for your problem.
First off, to answer your question about the adapter pattern, it doesn't apply here. You use the adapter pattern to add a layer between 2 incompatible systems to allow them to pass data back and forth.
Using your example, I would recommend writing default implementations of the hasPassed_() methods in Assessor, even if the implementation is nothing more than throwing a new UnsupportedOperationException (to answer the question about what if a particular Assessor only needs a subset of hasPassed_() methods you can just overwrite only the ones you need). You can modify the subject assessor's (e.g. MathAssessor, EnglishAssessor, etc.) Pass methods to be more specific or to provide additional checks before calling super.hasPassed_() (depending on your specific implementation).
I see code like this
class A implements Comparable<A> {
}
What does this mean, what are the advantages and disadvantages of it?
It means that class is committed to respond to the methods defined by the "interface" Comparable.
The advantage you have with this ( and any other "implements" declaration ) it that you can "abstract" the type of the object and code to the interface instead.
Consider this
class A implements Comparable {
....
}
class B implements Comparable {
....
}
class C implements Comparable {
....
}
You then may code something that can use Comparable instead of a specific type:
public void doSomethingWith( Comparable c ) {
c.compareTo( other ); // something else...
}
And invoke it like:
doSomethingWith( new A() );
doSomethingWith( new B() );
doSomethingWith( new C() );
Because you don't really care what the type of the class is, you just care it does implement the interface.
This ( program to the interface rather to the implementation ) is one of the most powerful techniques in OO programming world, because it promotes low-coupling.
Implementing a comparable interface means that A can be compared with other instances of A.
Many operations in java that involve sorting use the methods defined in the Comparable interface to determine if instances of A are greater then less or equal to other instances.
By implementing these methods you are able to use a lot of handy features such as java sort, use instances of A as keys for binary trees, and more.
It means that class A can be sorted using the Comparable compareTo method:
A a1 = new A(1);
A a2 = new A(3);
// -1, 0, or 1 depending on whether a2 is less than, equal to, or greater than a1
int order = a1.compareTo(a2);
Comparable uses the natural ordering for your class.
Another way to go since Java 5 is Comparator. You can pass this object around and have more than one way to compare and sort the target class. For example, sometimes you might want to sort a Name class by first name, other times by last name. Comparable only gives you one way to do it, but you can have several Comparator instances.
It means that the class is one which can be operated on by functions which expect their arguments to be objects that can be compared with other objects of the same type (such as the pre-defined sorting functionality for lists).
Implementing the Comparable interface means that the class supports certain functions which the interface requires (specifically, the compareTo() method), that the sorting (or other) operations being performed on the class will utilize to do their work without having to care about the rest of the class.
For more details:
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Comparable.html
In addition to what everyone else said, by implementing an interface (or extending a class), you get compiler enforcement of the contract of the supertype. In the case of 'Comparable', that means that you get a compiler error if you fail to implement the 'int compareTo(A anA)' method in the implementing class. Adding the annotation '#Override' to the implementing method provides even more compile-time safety; if you fail to implement the method with the right signature the compiler will tell you. Compile-time errors are much, much easier and cheaper to fix than run-time errors. Furthermore, implementing an interface allows any instance of an implementing class to be treated as the interface type for methods (and constructors) that take the interface type as an argument or generic parameter. For example, the 'java.util.Collections.max(Collection coll)' method takes a collection whose base type must extend 'Comparable'.
http://download.oracle.com/javase/7/docs/api/java/util/Collections.html#max(java.util.Collection)
It means that objects of this class can be easily sorted in collections because they can be compared to each other. The other option is to implement a Comparator which is a class responsible for sorting other classes. The Comparable puts the sorting logic directly in the class to be sorted; the Comparator puts the sorting logic in a different class.