我还是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并在每个子类中覆盖它,但由于它是使用集合的世界,这似乎也很糟糕
对于什么是“优雅”/好的解决方案,我感到很茫然。
答案 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方法)。您是否真的想要这样做,将取决于您的实际应用