保持类独立性或避免类型检查

时间:2013-05-11 12:22:44

标签: java optimization typechecking

我还是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并在每个子类中覆盖它,但由于它是使用集合的世界,这似乎也很糟糕

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

2 个答案:

答案 0 :(得分:1)

你是绝对正确的,这种编程方式会立即破坏你代码的可维护性。

有两种简单的方法可以解决这个问题 - 实施visitor,并根据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);
    });
}

答案 1 :(得分:0)

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