2013-05-11 70 views
2

我仍然是java的初学者,但我尝试编写好的代码(obj oriented)。但是,我遇到了方法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移动到动物并覆盖它在每个子类,但因为它是使用套的世界,这似乎不好,以及

我很不知道什么是“优雅”/良好的解决方案。

+1

首先要做的事情:解决您的压痕以提高可读性,遵循Java的命名约定,并使用泛型。下一步:解释*为什么*你想要一组长颈鹿和一匹斑马等。这背后的推理是什么? – 2013-05-11 12:24:56

+0

我认为我修正了缩进和命名,不完全确定泛型所代表的含义。我需要这些集合来遍历它们并检查可能的交互(与所有其他长颈鹿一起进入该领域的进程)。 – Wouter 2013-05-11 12:48:55

回答

1

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

有两种简单的方法来处理这个问题 - 实现visitor,并根据Class<T>定义Map

这是第一种方法的一个例子:

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); 
    }); 
} 
+0

是否可以使用此映射返回一组类型Set ? (这严格来说是一个我认为是问题的问题,所以如果违反规则,只是通知我,我会删除评论,并将其作为一个独立的问题) – Wouter 2013-05-13 18:53:22

+0

@Wouter虽然这是一个单独的问题,指出单独提问,因为它会是重复的。在Java中,泛型通过* type erasure *来实现,这意味着一旦放置在Map中,'Set '与'Set '不可区分。尽管如此,如果您将无类型集放置在“Map”中,您将无法从泛型中获得任何好处。 – dasblinkenlight 2013-05-13 19:10:44

+0

所以我将不得不遍历整个集合,解析元素并将它们添加到新的集合中? (我在一个界面里面工作,我不能改变) – Wouter 2013-05-13 19:30:20

0

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

+0

我不知道你为什么接受其他答案;这一个更容易,做你想做的事情。更简单地说:用一个空的removeFromWorld()创建一个Animal抽象类,然后在每个动物的子类中实现removeFromWorld()。 – arcy 2013-05-11 13:51:12

+0

按课程创建地图似乎是一个更方便的解决方案,因为如果我愿意,我可以更容易地访问所有不同的集合。我也认为将这个方法放在世界的removeWorld中会更有意义(正如我在我的问题中所述)。但感谢您指出,如果使用地图(或访问者)证明是一种痛苦,我可能需要重新考虑。 – Wouter 2013-05-11 14:36:16

+0

@Wouter我倾向于同意。我的回答实现了将优雅的mannor中的removeFromWorld移动到Animal类中。然而,对于您的应用程序,我认为dasblinkenlight的第二个答案是最合适的 – 2013-05-11 15:04:03