1

I have read Item 16 from Effective Java and Prefer composition over inheritance? and now try to apply it to the code written 1 year ago, when I have started getting to know Java.

I am trying to model an animal, which can have traits, i.e. Swimming, Carnivorous, etc. and get different type of food.

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

}

In Item 16 composition-and-forwarding reuseable approach is suggested:

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
}

I can implement ForwardingList<E> but I am not sure on how I would apply it twice for Animal class. Now in Animal I have many methods like below for traits and also for eatenFood. This seems akward to me.

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

public boolean removeTrait (Trait trait) {
    return traits.remove(trait);
}
  1. How would you redesign the Animal class?

  2. Should I keep it as it is or try to apply ForwardingList?

Community
  • 1
  • 1
Nikolay Kuznetsov
  • 9,467
  • 12
  • 55
  • 101

1 Answers1

1

There is no reason you'd want to specialize a List for this problem. You are already using Composition here, and it's pretty much what I would expect from the class.

Composition is basically creating a class which has one (or usually more) members. Forwarding is effectively having your methods simply make a call to one of the objects it holds, to handle it. This is exactly what you're already doing.

Anyhow, the methods you mention are exactly the sort of methods I would expect for a class that has-a Trait. I would expect similar addFood / removeFood sorts of methods for the food. If they're wrong, they're the exact sort of wrong that pretty much everyone does.

IIRC (my copy of Effective Java is at work): ForwardingSet's existence was simply because you cannot safely extend a class that wasn't explicitly designed to be extended. If self-usage patterns etc. aren't documented, you can't reasonably delegate calls to super methods because you don't know that addAll may or may not call add repeatedly for the default implemntation. You can, however, safely delegate calls because the object you are delegating to will never make a call the wrapper object. This absolutely doesn't apply here; you're already delegating calls to the list.

Nikolay Kuznetsov
  • 9,467
  • 12
  • 55
  • 101
James
  • 8,512
  • 1
  • 26
  • 28