I designed the following for a problem:
class Animal {
// ...
}
class Guppy extends Animal { ... }
class Pigeon extends Animal { ... }
class TailedAnimal extends Animal {
// ...
}
class Dog extends TailedAnimal { ... }
class Cat extends TailedAnimal { ... }
class HornedAnimal extends Animal {
// ...
}
class Ram extends HornedAnimal { ... }
public static void main(String[] args) {
Animal a = getSomeAnimal();
a.doSomething();
if (a instanceof TailedAnimal) {
// do something
}
if (a instanceof HornedAnimal) {
// do something else
}
}
Animal, HornedAnimal and TailedAnimal are used mainly as data models.
Since Java does not support multiple inheritance, I have trouble creating Rhinoceros which is a Horned and Tailed animal. After asking around, someone recommended using composition and interfaces. I came up with the following:
class Animal {
// ...
}
class Guppy extends Animal { ... }
class Pigeon extends Animal { ... }
class Ram extends Animal implements IHorned { ... }
class Cat extends Animal implements ITailed { ... }
class Dog extends Animal implements ITailed {
BasicTail t = new BasicTail();
public Object getTail() {
return t.getTail();
}
public void setTail(Object in) {
t.setTail(in);
}
}
interface ITailed {
public Object getTail();
public void setTail(Object in);
//...
}
class BasicTail implements ITailed {
Object myTail;
public Object getTail() { return myTail; }
public void setTail(Object t) { myTail = t; }
}
interface IHorned {
// getters and setters
}
public static void main(String[] args) {
Animal a = getSomeAnimal();
a.doSomething();
// how do I check if a is horned or tailed?
}
My interface has getters and setters. Is there any way to avoid this? Assuming that there is currently no way to abstract the behaviour of Tails and Horns, and they're are being used mainly as data holders. How do I determine if my Animal is Horned or Tailed?
I think you must avoid setters in general. If you can, use immutable objects, and initialize its private data into its constructor.
To distinguish animals, I used another pattern, the visitor one. It's verbose, but you don't have to test directly what animal you're processing.
public class Animals {
private Animals() {
}
interface Animal {
void accept(final AnimalProcessor visitor);
}
interface AnimalProcessor {
void visitTailed(final TailedAnimal tailedAnimal);
void visitHorned(final HornedAnimal hornedAnimal);
}
interface TailedAnimal extends Animal {
void moveTail();
}
interface HornedAnimal extends Animal {
void hitWithHorns();
}
static class Dog implements TailedAnimal {
public void moveTail() {
//To change body of implemented methods use File | Settings | File Templates.
}
public void accept(final AnimalProcessor visitor) {
visitor.visitTailed(this);
}
}
static class Cat implements TailedAnimal {
public void moveTail() {
//To change body of implemented methods use File | Settings | File Templates.
}
public void accept(final AnimalProcessor visitor) {
visitor.visitTailed(this);
}
}
static class Ram implements HornedAnimal {
public void hitWithHorns() {
//To change body of implemented methods use File | Settings | File Templates.
}
public void accept(final AnimalProcessor visitor) {
visitor.visitHorned(this);
}
}
static class Rhinoceros implements HornedAnimal, TailedAnimal {
public void hitWithHorns() {
//To change body of implemented methods use File | Settings | File Templates.
}
public void moveTail() {
//To change body of implemented methods use File | Settings | File Templates.
}
public void accept(final AnimalProcessor visitor) {
visitor.visitTailed(this);
visitor.visitHorned(this);
}
}
public static void main(String[] args) {
Collection<Animal> animals = new ArrayList<Animal>(Arrays.asList(new Dog(), new Cat(), new Rhinoceros()));
for (final Animal animal : animals) {
animal.accept(new AnimalProcessor() {
public void visitTailed(final TailedAnimal tailedAnimal) {
// you do what you want when it's a tailed animal
}
public void visitHorned(final HornedAnimal hornedAnimal) {
// you do what you want when it's a horned animal
}
});
}
}
}