我已阅读《Effective Java》中的第 16 条并且 Prefer composition over inheritance?现在尝试将其应用到 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
类(class)。现在在Animal
我有很多类似下面的方法 traits
也适用于eatenFood
。这对我来说似乎很尴尬。
public boolean addTrait (Trait trait) {
return traits.add(trait);
}
public boolean removeTrait (Trait trait) {
return traits.remove(trait);
}
您将如何重新设计
Animal
类(class)?我应该保持原样还是尝试申请
ForwardingList
?
最佳答案
您没有理由想专门使用一个列表来解决这个问题。您已经在这里使用了“组合”,这几乎正是我对类(class)的期望。
组合基本上是创建一个具有一个(或通常多个)成员的类。转发实际上是让您的方法简单地调用它所持有的对象之一来处理它。这正是您已经在做的事情。
无论如何,您提到的方法正是我所期望的具有 Trait 的类的方法。我期望类似的 addFood/removeFood 类型的食物方法。如果他们错了,那也是几乎每个人都犯过的错误。
IIRC(我的Effective Java 副本正在工作):ForwardingSet 的存在只是因为您无法安全地扩展未明确设计为扩展的类。如果未记录自使用模式等,则您无法合理地将调用委托(delegate)给 super 方法,因为您不知道 addAll 可能会也可能不会为默认实现重复调用 add 。但是,您可以安全地委托(delegate)调用,因为您委托(delegate)的对象永远不会调用包装器对象。这绝对不适用于这里;您已将调用委托(delegate)给该列表。
关于java - 具有两个列表的类的组合和转发方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15105295/