我正在为如何避免在我的一些代码中使用instanceof()而苦苦挣扎。这个人为的例子在某种程度上抓住了这个问题。
Class Meat extends Food;
Class Plant extends Food;
Class Animal;
Class Herbivore extends Animal
{
void eat( Plant food);
}
Class Carnivore extends Animal
{
void eat( Meat food);
}
Class Omnivore extends Animal
{
void eat(Food food);
}
Class Zoo
{
List<Animals> animals;
void receiveFood( Food food)
{
// only feed Plants to Herbivores and Meat to Carnivores
// feed either to Omnivores
}
}草食动物只对植物感兴趣,肉食动物只对肉类和杂食动物都感兴趣。当动物园收到食物时,只有尝试给吃这种食物的动物喂食才有意义。
我已经想出了一些解决方案,但似乎都依赖于instanceof()的使用,而我的各种重构似乎只是改变了它。
(1)我可以在动物类中实现eat( Food food),每个子类可以选择忽略它不吃的食物,但这是低效的,并且需要每个动物子类使用instanceof()来测试食物的类型。
(2)我可以根据动物吃的食物类型在动物园中保存三个动物集合,但仍然需要使用instanceOf()来测试食物的类型,以确定要喂给哪个集合。至少这会更有效率,因为我不会给不吃的动物喂食。
我想过一些其他的方法,但同样,它们似乎只是推卸了instanceof()的责任。
有什么建议吗?或者这(至少2个)是instanceof()可以接受的用法
发布于 2012-04-05 04:14:46
访问者模式解决了您的问题。代码如下:
public abstract class Animal {
public abstract void accept(AnimalVisitor visitor);
}
public interface AnimalVisitor {
public void visit(Omnivore omnivore);
public void visit(Herbivore herbivore);
public void visit(Carnivore carnivore);
}
public class Carnivore extends Animal {
@Override
public void accept(AnimalVisitor visitor) {
visitor.visit(this);
}
public void eat(Meat meat) {
System.out.println("Carnivore eating Meat...");
}
}
public class Herbivore extends Animal {
@Override
public void accept(AnimalVisitor visitor) {
visitor.visit(this);
}
public void eat(Plant plant) {
System.out.println("Herbivore eating Plant...");
}
}
public class Omnivore extends Animal {
@Override
public void accept(AnimalVisitor visitor) {
visitor.visit(this);
}
public void eat(Food food) {
System.out.println("Omnivore eating " + food.getClass().getSimpleName() + "...");
}
}
public abstract class Food implements AnimalVisitor {
public void visit(Omnivore omnivore) {
omnivore.eat(this);
}
}
public class Meat extends Food {
@Override
public void visit(Carnivore carnivore) {
carnivore.eat(this);
}
@Override
public void visit(Herbivore herbivore) {
// do nothing
}
}
public class Plant extends Food {
@Override
public void visit(Carnivore carnivore) {
// do nothing
}
@Override
public void visit(Herbivore herbivore) {
herbivore.eat(this);
}
}
public class Zoo {
private List<Animal> animals = new ArrayList<Animal>();
public void addAnimal(Animal animal) {
animals.add(animal);
}
public void receiveFood(Food food) {
for (Animal animal : animals) {
animal.accept(food);
}
}
public static void main(String[] args) {
Zoo zoo = new Zoo();
zoo.addAnimal(new Herbivore());
zoo.addAnimal(new Carnivore());
zoo.addAnimal(new Omnivore());
zoo.receiveFood(new Plant());
zoo.receiveFood(new Meat());
}
}运行Zoo演示打印
Herbivore eating Plant...
Omnivore eating Plant...
Carnivore eating Meat...
Omnivore eating Meat...发布于 2012-04-05 03:13:25
在你的例子中,如果对象的消费者必须知道关于该对象的某些事情(例如它是肉),在你的基类isMeat()中包含一个属性,并让具体的子类覆盖基类方法的实现,以返回适当的值。
把知识留给类本身,而不是类的消费者。
发布于 2012-04-05 03:14:12
一个简单的解决方案是,当使用多个自定义类相互交互时,只需创建isFood()、isAnimal()、isCarnivore()等方法,这些方法根据它们所在的类返回一个布尔值。它不是最漂亮的,但它可以100%地完成工作。
https://stackoverflow.com/questions/10017703
复制相似问题