我有一个Animal对象的集合。
我的核心代码希望将所有这些都视为动物,都是一样的。每种动物都需要以某种方式进行处理。加工的性质取决于动物的亚型(鸟类,哺乳动物等)。
我的代码目前看起来如下。
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子类中的向下转换!这使我感到不应该存在,并且可能违反OO原则。毕竟,目前我可以将Bird传递给MammalProcessor的process()方法,并且会有一个ClassCastException。
有人可以建议设计模式来解决这个问题吗?我查看了访客模式,但在这种情况下无法弄清楚如何应用它!关键是要使核心代码(ZooKeeper)对所有动物进行相同的处理,并使其能够平凡地添加对新动物的支持。谢谢!
答案 0 :(得分:1)
我建议如下:
public interface Animal {
public String getTaxonomyClass();
public void process();
}
现在每个实现Animal的动物类都应该实现自己的处理逻辑。 例如:
public class Bird implements Animal {
public Bird(float wingSpan) {
this.wingSpan = wingSpan;
}
@Override
public String getTaxonomyClass() {
return "aves";
}
@Override
public void process() {
System.out.print("Wingspan is " + wingSpan);
}
// Specific to birds
private float wingspan;
}
现在您只能拥有一个处理如下的AnimalProcessor:
public void process(Animal a) {
a.process();
}
答案 1 :(得分:1)
我建议如下:
public interface Animal {
public AnimalProcessor<? extends Animal> getProcessor();
}
所以每只动物都会返回它的匹配处理器。
public interface AnimalProcessor<T extends Animal> {
public void process(T a);
}
所以处理器将输入它应该处理的匹配类型。 植入将是这样的:
public abstract class Bird implements Animal {
private BirdProcessor processor = new BirdProcessor();
public abstract float getWingspan();
@Override
public AnimalProcessor<Bird> getProcessor() {
return processor;
}
}
public class BirdProcessor implements AnimalProcessor<Bird> {
@Override
public void process(Bird b) {
System.out.print("Wingspan is " + b.getWingspan());
}
}
答案 2 :(得分:1)
这是generics工作得很好的地方。
首先,您需要使AnimalProcessor成为通用的:
public interface AnimalProcessor <T extends Animal> {
public String getSupportedTaxonomyClass();
public void process(T a);
}
接下来,在您的特定处理器中,您指定通用类型 - 例如哺乳动物:
public class MammalProcessor implements AnimalProcessor<Mammal> {
public String getSupportedTaxonomyClass() {
return "mammalia";
}
public void process(Mammal a) {
System.out.println("Tooth count is " + a.getToothCount());
}
}
现在,处理方法只接受哺乳动物对象,这里没有鸟类。
答案 3 :(得分:1)
让你AnimalProcessor
通用;
public interface AnimalProcessor<T extends Animal> {
public String getSupportedTaxonomyClass();
public void process(T a);
}
public class MammalProcessor implements AnimalProcessor<Mammal> {
@Override
public String getSupportedTaxonomyClass() {
return "mammalia";
}
@Override
public void process(Mammal a) {
System.out.println("Tooth count is " + a.getToothCount());
}
}
答案 4 :(得分:0)
所以你有一个这样的课......
public abstract class Bird implements Animal {
@Override
public String getTaxonomyClass() {
return "aves";
}
// Specific to birds
public abstract float getWingspan();
}
即使翼展为Birds
,所有0
也会有翼展。那么,你为什么不把班级变成这样的......
public class Bird implements Animal {
float wingspan = 0.0f;
public Bird(float wingspan){
this.wingspan = wingspan;
}
@Override
public String getTaxonomyClass() {
return "aves";
}
// Specific to birds
public float getWingspan(){
return wingspan;
}
}
所以,要创建一个新的Bird
,而不是这样做......
animals.add(new Bird() { // condor
@Override
public float getWingspan() {
return 2.9f;
} }
);
你会这样做......
animals.add(new Bird(2.9f)); // condor
这似乎会使整个事情变得更简单,更适合您的目的。您也会对Mammal
课程进行类似的更改。
现在,对于动物的处理......如果要处理所有Animals
,您可以在process()
中实施Bird
,而不是需要单独的BirdProcessor
}类。为此,请在Animal
中声明方法public void process();
。您的Bird
会像这样实现它......
public void process() {
System.out.print("Wingspan is " + getWingspan());
}
你会改变你的AnimalProcessor
来执行此操作(注意:不再是界面)......
public class AnimalProcessor {
public void process(Animal a) {
a.process();
}
}
您的AnimalProcessor
课程将可以处理所有Animals
。
或者,如果您希望保留AnimalProcessor
,可能最好更改以下内容,以避免ClassCastException
(此代码适用于BirdProcessor
)...
public void process(Animal a) {
if (a instanceof Bird){
System.out.print("Wingspan is " + ((Bird)a).getWingspan());
}
}
这有点像你在找什么?
答案 5 :(得分:0)
您的问题是
等方法 public abstract int getToothCount();
...未在Animal中定义。相反,它们在Animal的特定子类中定义。这意味着你不能一般地对待动物,因为它们根本不同。
为了克服这个问题,一种方法是在Animal类中为所有这些创建抽象方法。
Bird可能会以“0”响应getToothCount()。
由于所有动物都可以响应getWingspan(),getTootCount()等,因此您不必执行任何特定于类型的检查。如果这还不够好,请在Animal中创建“boolean hasWings()”,“boolean hasTeeth()”等的抽象实现。
现在你可以说,对某些动物来说:
if (a.hasWings()) System.out.println("My wingspan is "+a.getWingSpan());
适用于任何动物。当然,Animal的每个子类都必须实现所有各种方法。
另一种选择是向Animal添加非抽象方法。这些方法将提供默认答案。例如,getWingSpan()将返回0,getToothCount()将返回0,等等.Shark将覆盖getToothCount()。 Eagle会覆盖getWingSpan()......
然后你的子类只需要覆盖(甚至知道)直接与它们相关的方法。