views:

300

answers:

2

I may have designed myself into a corner with this problem but I feel like there's a workable known solution to something like this that I'm not seeing. It may well be that I'm completely overcomplicating the problem and skipped over the obvious solution. Any advice would be greatly appreciated.

I have a set of entities defined as interfaces. Each has a concrete implementation and a wrapper implementation. For example:

-- Foo.java
public interface Foo {
    public String getName();
}

-- FooImpl.java
public class FooImpl implements Foo {
    private String name;

    public String getName() {
        return name;
    }
}

-- AbstractWrapper.java
public class AbstractWrapper {
     protected String decorate(String text) {
         return "** " + text + " **";
     }

-- FooWrapper.java
public class FooWrapper extends AbstractWrapper implements Foo {
    private Foo wrappedFoo;

    public FooWrapper(Foo wrappedFoo) {
         this.wrappedFoo = wrappedFoo;
    }

    public String getName() {
         return decorate(wrappedFoo.getName());
    }
}

Now, the part that's complicating the situation is that I'm trying to make a List that automatically wraps the appropriate type with its appropriate wrapper before adding it. Something like:

-- WrappingList.java

/** T is the base entity interface type. */
public class WrappingList<T> implements List<T> {
    private List<T> wrappedList;

    public WrappingList(List<T> wrappedList) {
        this.wrappedList = wrappedList;
    }

    ....

    public boolean add(T item) {
        return wrappedList.add(wrapItem(item));
    }

    protected T wrapItem(T item) {
         T wrappedItem = .....;
         return T;
    }
}

Is there anything I can do to make a somewhat clean factory method here? Or am I already out of luck at this point because of type erasure?

+1  A: 

I think you should add a WrapperFactory to your WrappingList, and provide the actual factory implementation in the constructor. Something like:

-- WrapperFactory.java
public class WrapperFactory<T> {

   public T wrap(T item);

}

-- WrappingList.java
/**
 * A self-wrapping list.
 *
 * @param T the stored, wrapped item type
 */
public class WrappingList<T> implements List<T> {
    private List<T> wrappedList;
    private WrapperFactory<T> wrapper;

    public WrappingList(List<T> wrappedList, WrapperFactory<T> wrapper) {
        this.wrappedList = wrappedList;
        this.wrapper = wrapper;
    }

    ....

    public boolean add(T item) {
        return wrappedList.add(wrapper.wrap(item));
    }

}

The basic problem is that erasure won't let you know anything about T in the actual code, so unless you pass something to your list that knows about the specific T you are using (e.g. how to wrap it) you won't be able to do anything. And it's not designing you in a corner ;) it's simply a common limitation of Java generics.

Varkhan
I think this is the answer that was in the back of my head and bugging me that it should be possible. It definitely works here. Thanks!
Jon
A: 

Yeah, I ran into this type of thing too. I have concluded that entities ought not to be wrapped in interfaces. An entity - a mutable value bean - is not a service, and wrapping it just causes endless grief.

Interfaces mean that every methos that nominally returns a list of beans - a very common thing - has to be declared as returning List<? extends BeanInterface>, and you have to provide methods whose job it is to create new elements in these lists (you can't just put a bean in there). Pain in the proverbial.

Use interfaces sparingly when entities really do implement some common pattern shared among some of your entities.

paulmurray
I agree in general -- this was actually a refactoring in the first place because I needed to make certain entities Observable in a subclass.
Jon