Suppose you have a Java class hierarchy of about 30 classes, with a base class BaseClass and two main subclasses (SubclassA, SubclassB) with several subclasses each. A few of these subclasses have a certain behavior. Let’s say you can “poke” them, changing their state. (This is a new requirement adding behavior to an existing hierarchy. “Poke” is meaningless to the majority of classes.)
interface Pokeable {
void poke();
int getTimesPoked();
}
public class Pokey extends SubclassB
implements Pokeable {
private int timesPoked = 0;
public void poke() {
timesPoked++;
}
public int getTimesPoked() {
return timesPoked;
}
}
Should this be done by implementing Pokeable in only those classes that need it, and then doing the following in all code that must poke any object that’s pokeable?
public void process(BaseClass b) {
if (b instanceof Pokeable) {
((Pokeable)b).poke();
}
}
Or should the entire hierarchy implement Pokeable for the sake of the few that really ARE Pokeable?
interface Pokeable {
void poke();
int getTimesPoked();
boolean isReallyPokeable();
}
public class BaseClass implements Pokeable {
public void poke() {}
public int getTimesPoked() { return 0; }
public boolean isReallyPokeable() { return false;}
}
public class Pokey {
private int timesPoked = 0;
@Override
public void poke() {
timesPoked++;
}
@Override
public int getTimesPoked() {
return timesPoked;
}
@Override
public boolean isReallyPokeable() {
return true;
}
}
public void process(BaseClass b) {
b.poke();
}
Edit added: It’s kind of a Double Dispatch problem. Where “poker” code does something to an object, it must call “poke()” if the object is “pokeable” but can’t if not. Whether you “poke()” or not depends on whether something wants to poke and whether the object accepts being poked. I could use the Visitor pattern but that seems to make it more complicated.
If a class is not pokable, I would recommend against it implementing the
Pokeableinterface, simply because that would be confusing.Take one of the following approaches instead.
BaseClassthat implementsPokable, and have all of your to-be-Pokeablesubclasses extend it. This approach works well ifpoke()ing is achieved via the same logic in all of the implementing classes.Pokeableindividually