In your example, move()
belongs to the Vehicle
interface and defines the contract "going from point A to point B".
When GroundVehicle
and WaterVehicle
extend Vehicle
, they implicitly inherit this contract (analogy: List.contains
inherits its contract from Collection.contains
-- imagine if it specified something different!).
So when the concrete AmphibianVehicle
implements move()
, the contract it really needs to respect is Vehicle
's. There is a diamond, but the contract doesn't change whether you consider one side of the diamond or the other (or I would call that a design problem).
If you need the contract of "moving" to embody the notion of surface, don't define it in a type that doesn't model this notion:
public interface GroundVehicle extends Vehicle {
void ride();
}
public interface WaterVehicle extends Vehicle {
void sail();
}
(analogy: get(int)
's contract is defined by the List
interface. It couldn't possibly be defined by Collection
, as collections are not necessarily ordered)
Or refactor your generic interface to add the notion:
public interface Vehicle {
void move(Surface s) throws UnsupportedSurfaceException;
}
The only problem I see when implementing multiple interfaces is when two methods from totally unrelated interfaces happen to collide:
public interface Vehicle {
void move();
}
public interface GraphicalComponent {
void move(); // move the graphical component on a screen
}
// Used in a graphical program to manage a fleet of vehicles:
public class Car implements Vehicle, GraphicalComponent {
void move() {
// ???
}
}
But then that wouldn't be a diamond. More like an upside-down triangle.