2

我仍然是java的初学者,但我尝试编写好的代码(面向obj)。但是,我的方法有问题removeFromWorld。我有几种方法,但无论我做什么,我似乎都打破了良好编程实践的“规则”。

我尝试了类型检查:

    public class World{
        private Set setGiraffes;
        public void removeFromWorld(Animal animal){
            if (isGiraffe(animal))
                setGiraffes.remove((Giraffe) animal)
            else if (isZebra(animal)){...}
        else if ...
        }
    }
    public abstract class Animal{..}

    public class Giraffe extends Animal{..}

但听说这是个坏主意,因为在不改变现有方法的情况下添加新动物是不可能的。我考虑过转移removeFromWorld到 Animal 并在每个子类中覆盖它,但由于它是 World 使用集合,这似乎也很糟糕

对于什么是“优雅”/好的解决方案,我感到很茫然。

4

2 回答 2

1

你是绝对正确的,这种编程风格会立即扼杀代码的可维护性。

有两种简单的方法来处理这个问题——实现一个访问者和定义一个Map基于Class<T>

这是第一种方法的示例:

interface Visitor {
    void visitGiraffe(Giraffe g);
    void visitZebra(Zebra z);
}
abstract class Animal {
    public abstract void accept(Visitor v);
}
class Giraffe extends Animal {
    public void accept(Visitor v) {
        v.visitGiraffe(this);
    }
}
class Zebra extends Animal {
    public void accept(Visitor v) {
        v.visitZebra(this);
    }
}

有了这个结构,你可以编写你的移除器,如下所示:

void removeFromWorld(Animal a) {
    a.accept(new Visitor() {
        public void visitGiraffe(Giraffe g) {
            setOfGiraffes.remove(g);
        }
        public void visitZebra(Zebra z) {
            setOfZebras.remove(z);
        }
    });
}

第二个依赖于 Java 对象生成它们的Class. 现在而不是定义

Set<Giraffe> setOfGiraffes = ...
Set<Zebra> setOfZebras = ...

你可以定义

Map<Class,Set<Animal>> setOfAnimalByClass = ...

要访问长颈鹿,你会做

setOfAnimalByClass.get(Giraffe.class).add(new Giraffe());

等等。然后你可以removeFromWorld这样实现:

void removeFromWorld(Animal a) {
    a.accept(new Visitor() {
        setOfAnimals.get(a.getClass()).remove(a);
    });
}
于 2013-05-11T12:32:40.327 回答
0

假设所有动物都有一个removeFromWorld方法,但每个孩子都有不同的版本,那么优雅的解决方案是创建Animal一个抽象类和removeFromWorld一个抽象方法。这样,任何扩展的类Animal都必须有自己的removeFromWorld方法(并且不能意外使用通用的 Animal 方法)。您是否真的想这样做取决于您的实际应用程序

于 2013-05-11T12:31:27.947 回答