動物オブジェクトのコレクションがあります。
私のコア コードでは、これらすべてを同じように動物として扱いたいと考えています。各動物は何らかの方法で処理する必要があります。処理の性質は、動物のサブタイプ (鳥、哺乳類など) によって異なります。
私のコードは現在次のようになっています。
public interface Animal {
public String getTaxonomyClass();
}
public abstract class Bird implements Animal {
@Override
public String getTaxonomyClass() {
return "aves";
}
// Specific to birds
public abstract float getWingspan();
}
public abstract class Mammal implements Animal {
@Override
public String getTaxonomyClass() {
return "mammalia";
}
// Specific to mammals
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))
{
// if I can process the animal, I will
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() { // badger
@Override
public int getToothCount() {
return 40;
} }
);
animals.add(new Bird() { // condor
@Override
public float getWingspan() {
return 2.9f;
} }
);
keeper.processNewAnimals(animals);
}
}
一般的に、これは理解しやすく、うまく機能します。ZooKeeper クラスやインターフェイスを変更することなく、プラグインの新しいプロセッサと動物の種類を自由に追加できます。データベースから動物をロードし、それらすべてを順番に処理する、より高度なメイン クラスを想像できます。
ただし、AnimalProcessor サブクラス内のダウンキャストが心配です! これはあってはならないことであり、オブジェクト指向の原則に違反している可能性があります。結局、現時点では鳥を MammalProcessor の process() メソッドに渡すことができ、ClassCastException が発生します。
これを解決するための設計パターンを提案できる人はいますか? Visitor パターンを見ましたが、この場合の適用方法がよくわかりませんでした! 重要なのは、コア コード (ZooKeeper) ですべての動物を同じように扱い、新しい動物のサポートを簡単に追加できるようにすることです。ありがとう!