samedi 14 juillet 2018

Java generics - too complicated? How to simplify?

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

I'm coding for a multi-step process. 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?

Aucun commentaire:

Enregistrer un commentaire