I’m choosing between the following 2 designs. Which would you recommend and why?
I’m quite doubtful about placing get/set methods in interfaces in the second method. Any comments about this?
public class Foo {
Time time;
boolean hasTime();
Time getTime() { return time; }
void setTime() { this.time = time; }
}
public class Bar extends Foo {
boolean hasTime() { return true; }
}
public class Baz extends Foo {
boolean hasTime() { return false; }
}
main() {
for (Foo foo : foos) {
if (foo.hasTime()) {
// do something
}
}
}
vs
public class Foo {
}
public class Bar extends Foo implements TimedObject {
Time time;
Time getTime() { return time; }
void setTime() { this.time = time; }
}
public interface TimedObject {
Time getTime();
void setTime();
}
main() {
for (Foo foo : foos) {
if (foo instance of TimedObject) {
// do something
}
}
}
The second approach is definitely the better.
In the first approach, the getters and setters exist in both Bar and Baz classes, and can be called … irrespective of what
hasTime()returns!You could override the getter and setter in
Bazso that they threw (for instance) anOperationNotSupportedexception. But even that’s a bit “icky”:If you compare how a program would use the two versions, the first one requires you to remember to call
hasTime(), whereas with the second one the compiler will tell you if you forget to typecast to a type that is assignment compatible withTimedObject.The first version violates the substitutability principle because
Bazwould behave in a way that is incompatible with its superclassFoo.