1

我已经阅读了 Effective Java 中的第 16 条,并且 更喜欢组合而不是继承?现在尝试将它应用到 1 年前编写的代码中,那时我已经开始了解 Java。

我正在尝试模拟一种动物,它可以具有特征,即游泳、食肉等,并获得不同类型的食物。

public class Animal {
    private final List<Trait> traits = new ArrayList<Trait>();
    private final List<Food> eatenFood = new ArrayList<Food>();

}

在第 16 条中,建议使用组合转发可重用方法:

public class ForwardingSet<E> implements Set<E> {
    private final Set<E> s;
    public ForwardingSet(Set<E> s) {this.s = s;}

    //implement all interface methods
    public void clear() {s.clear();}

    //and so on
}

public class InstrumentedSet<E> extends ForwardingSet<E> {
   //counter for how many elements have been added since set was created
}

我可以实现ForwardingList<E>,但我不确定如何在Animal课堂上应用两次。现在,Animal我有很多方法,例如下面的 fortraits和 for eatenFood。这对我来说似乎很尴尬。

public boolean addTrait (Trait trait) {
    return traits.add(trait);
}

public boolean removeTrait (Trait trait) {
    return traits.remove(trait);
}
  1. 你将如何重新设计Animal课程?

  2. 我应该保持原样还是尝试申请ForwardingList

4

1 回答 1

1

您没有理由要专门针对此问题使用列表。您已经在这里使用了 Composition,这几乎是我对课堂的期望。

组合基本上是创建一个具有一个(或通常更多)成员的类。转发实际上是让你的方法简单地调用它持有的对象之一来处理它。这正是您已经在做的事情。

无论如何,您提到的方法正是我所期望的具有 Trait 的类的方法。我希望食物有类似的 addFood / removeFood 方法。如果他们错了,他们就是几乎每个人都会犯的那种错误。

IIRC(我的 Effective Java 副本正在工作):ForwardingSet 的存在仅仅是因为您无法安全地扩展未明确设计为扩展的类。如果没有记录自我使用模式等,则无法合理地将调用委托给超级方法,因为您不知道 addAll 可能会或可能不会重复调用 add 以实现默认实现。但是,您可以安全地委托调用,因为您委托的对象永远不会调用包装器对象。这绝对不适用于这里;您已经将调用委托给列表。

于 2013-02-27T06:11:27.280 回答