java - 以类型特定的方式处理子类的正确模式是什么?

标签 java design-patterns subclass

我有一组 Animal 对象。

我的核心代码希望将所有这些都视为动物,都一样。每个 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 类或任何接口(interface)。您可以想象一个更高级的主类,从数据库中加载 Animals,然后依次处理它们。

但是,我担心 AnimalProcessor 子类中的向下转换!这让我觉得不应该存在,并且可能违反 OO 原则。毕竟,目前我可以将 Bird 传递给 MammalProcessor 的 process() 方法,并且会出现 ClassCastException。

谁能提出一个设计模式来解决这个问题?我查看了访问者模式,但不太明白如何在这种情况下应用它!关键是让核心代码 (ZooKeeper) 对所有动物一视同仁,这样就可以轻松添加对新动物的支持。谢谢!

最佳答案

我建议如下:

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());
    }
}

关于java - 以类型特定的方式处理子类的正确模式是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10534756/

相关文章:

javascript - 最佳实践导致臃肿的容器和非模块化代码

iOS : Best practices for Fields Validation on User Interface

go - 如何避免共享包的依赖循环?

oop - 从基类继承许多类是不好的 OOP 实践吗?

java - 是否可以在 Java 的方法中使用交替条件?

java - 在 InputStream 之前获取 FileSize

java - 类/方法 - 在 SDK 中删除/更改

java - 从批处理文件发出运行 java 程序,在 IDE 中运行良好

Java 编译速度 vs Scala 编译速度

python - 重新定义现有函数