I have a collection of Animal objects.
My main code wants it all to be treated as Animals, anyway. Each animal needs to be processed in some way. The nature of the treatment depends on the subtype of the animal (bird, mammal, etc.).
My code is as follows.
public interface Animal {
public String getTaxonomyClass();
}
public abstract class Bird implements Animal {
@Override
public String getTaxonomyClass() {
return "aves";
}
public abstract float getWingspan();
}
public abstract class Mammal implements Animal {
@Override
public String getTaxonomyClass() {
return "mammalia";
}
public abstract int getToothCount();
}
public interface AnimalProcessor {
public String getSupportedTaxonomyClass();
public void process(Animal a);
}
public class MammalProcessor implements AnimalProcessor {
@Override
public String getSupportedTaxonomyClass() {
return "mammalia";
}
@Override
public void process(Animal a) {
System.out.println("Tooth count is " + ((Mammal)a).getToothCount());
}
}
public class BirdProcessor implements AnimalProcessor {
@Override
public String getSupportedTaxonomyClass() {
return "aves";
}
@Override
public void process(Animal a) {
System.out.print("Wingspan is " + ((Bird)a).getWingspan());
}
}
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ZooKeeper {
Map<String, AnimalProcessor> registry = new HashMap<String, AnimalProcessor>();
public void registerProcessor(AnimalProcessor ap)
{
registry.put(ap.getSupportedTaxonomyClass(), ap);
}
public void processNewAnimals(List<Animal> newcomers)
{
for(Animal critter : newcomers)
{
String taxonomy = critter.getTaxonomyClass();
if(registry.containsKey(taxonomy))
{
AnimalProcessor ap = registry.get(taxonomy);
ap.process(critter);
}
}
}
}
import java.util.LinkedList;
import java.util.List;
public class MainClass {
public static void main(String[] args) {
ZooKeeper keeper = new ZooKeeper();
keeper.registerProcessor(new MammalProcessor());
keeper.registerProcessor(new BirdProcessor());
List<Animal> animals = new LinkedList<Animal>();
animals.add(new Mammal() {
@Override
public int getToothCount() {
return 40;
} }
);
animals.add(new Bird() {
@Override
public float getWingspan() {
return 2.9f;
} }
);
keeper.processNewAnimals(animals);
}
}
This is usually easy to understand and works great! I can add plugins for new processors and animal types at my leisure without changing the ZooKeeper class or any of the interfaces. You can imagine a more advanced main class by loading Animals from the database and processing them one at a time.
, AnimalProcessor! , , . , Bird mammalProcessor process(), ClassCastException.
- , ? , , ! (ZooKeeper) , , . !