Java generics - too complicated? How to simplify?

LppEdd :

Originally I had posted the question on CodeReview, but this is more suited for StackOverflow probably.

I'm coding for a multi-step process, using Java 6. Say there are 3 of these steps.
Each accepts the same type of input. Lets begin.

This is the object which is passed as input to each step. This object acts as a wrapper for another type of object, alongside some steps' shared values. Be aware names are translated to a more generic domain and in english, originals are in Italian.

public class EntityStepInput<T extends Entity> {
    public final T entity;
    public boolean modified;
    public boolean canceled;

    public EntityStepInput(final T entity) {
        this.entity = entity;
    }
}

This is the interface used by each step.

public interface EntityStep<T extends EntityStepInput<? extends Entity>> {
    void process(final T stepInput) throws Exception;
}

Now, 2 out of the 3 steps must accept an EntityStepInput which contains a Entity or any type derived from it.

public class FirstEntityStep implements EntityStep<EntityStepInput<? extends Entity>> {
    @Override
    public void process(final EntityStepInput<? extends Entity> stepInput) throws Exception {}
}

public class SecondEntityStep implements EntityStep<EntityStepInput<? extends Entity>> {
    @Override
    public void process(final EntityStepInput<? extends Entity> stepInput) throws Exception {}
}

The last step must accept an EntityStepInput which contains a specific type derived from Entity.

public class ThirdEntityStep implements EntityStep<EntityStepInput<? extends DerivedEntity>> {
    @Override
    public void process(final EntityStepInput<? extends DerivedEntity> stepInput) throws Exception {}
}

The usage is pretty straighforward. I have overloaded methods which accept different types of Entitys. What follows is a simplified version.

public void workWithEntity(final DerivedEntity entity) throws Exception {
    final EntityStepInput<DerivedEntity> stepInput = new EntityStepInput<DerivedEntity>(entity);

    stepOne.process(stepInput);
    stepTwo.process(stepInput);
    stepThree.process(stepInput);
}

As you can see the DerivedEntity type is able to use all of the steps.

public void workWithEntity(final OtherDerivedEntity entity) throws Exception {
    final EntityStepInput<OtherDerivedEntity> stepInput = new EntityStepInput<OtherDerivedEntity>(entity);

    stepOne.process(stepInput);
    stepTwo.process(stepInput);
}

And here another type of Entity cannot use the last step, which is what I want.

Now, this has became quite complex with generics. I fear who will read my code after I'm gone won't understand and sooner or later a mess is going to be made.

Is this simplifiable? What would your approach be like to respect as much as possibile the single responsibility principle?

Edit. Entity hierarchy is as follow:

Entity > DerivedEntity
Entity > OtherDerivedEntity
Radiodef :

One smaller change is just to simplify the type variable declaration on EntityStep to an Entity instead of an EntityStepInput:

interface EntityStep<E extends Entity> {
    void process(EntityStepInput<? extends E> i);
}

And then:

class FirstEntityStep implements EntityStep<Entity> {
    @Override
    public void process(EntityStepInput<? extends Entity> i) {}
}
class SecondEntityStep implements EntityStep<Entity> {
    @Override
    public void process(EntityStepInput<? extends Entity> i) {}
}
class ThirdEntityStep implements EntityStep<DerivedEntity> {
    @Override
    public void process(EntityStepInput<? extends DerivedEntity> i) {}
}

It's exactly the same as before, but the declarations are a bit easier to understand.

You'd only need T extends EntityStepInput<...> if you wanted to use some specific subclass, but since you always use EntityStepInput directly, you don't need it.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=36995&siteId=1