Java泛型-太复杂了吗?如何简化?

时间:2018-07-14 14:04:51

标签: java generics design-patterns

最初我在CodeReview上发布了该问题,但这可能更适合StackOverflow。

我正在使用Java 6为多步骤过程进行编码。假设其中有3个步骤。
每个接受相同类型的输入。 让我们开始吧。

这是作为输入传递到每个步骤的对象。除了某些步骤的共享值外,该对象还充当另一种对象的包装。 请注意,名称已翻译为更通用的域名,并且英文的原始名称为意大利语。

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

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

这是每个步骤使用的界面。

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

现在,三个步骤中的两个必须接受一个EntityStepInput,其中包含一个Entity或从其派生的任何类型。

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 {}
}

最后一步必须接受EntityStepInput,其中包含从Entity派生的特定类型。

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

用法非常简单。我有重载的方法,它们接受不同类型的Entity。接下来是简化版本。

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);
}

如您所见,DerivedEntity类型可以使用所有步骤。

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

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

在这里,另一种Entity无法使用我想要的最后一步。

现在,使用泛型已经变得相当复杂。我担心谁会在我走后阅读我的代码,这将不理解,迟早会造成混乱。

这可简化吗?在遵循单一责任原则的前提下,您希望采取什么方法?

编辑。 Entity的层次结构如下:

Entity > DerivedEntity
Entity > OtherDerivedEntity

2 个答案:

答案 0 :(得分:2)

这是我第二次尝试回答。我认为您当前使用的系统看起来不错;它提供了编译时检查,因为您不想让步骤3尝试处理不是DerivedEntity(或其子元素之一)的任何类型。

您可以使用List<Consumer<? extends Entity>>简化此操作,但是您会丢失对步骤#3的编译时类型检查,而不得不使用instanceof来改善它:

Java 8+解决方案:

List<Consumer<Entity>> processes = new ArrayList<>();

processes.add(entity -> {
    // Process first step.
});

processes.add(entity -> {
    // Process second step.
});

processes.add(entity -> {
    if (!(entity instanceof DerivedEntity)) {
        System.out.println("Step 3: The entity must be a DerivedEntity!");
        return;
    }
    // Process third step.
});

要通过管道传递Entity,就像这样简单:

processes.forEach(consumer -> consumer.accept(entity));

Java 6+解决方案(让我们创建自己的Consumer接口!)

public interface Consumer<T> {
    void accept(T t);
}

与上面相同的代码,但是使用我们的Consumer界面:

List<Consumer<Entity>> processes = new ArrayList<Consumer<Entity>>();

processes.add(new Consumer<Entity>() {
    @Override
    public void accept(Entity entity) {
        // Process first step.
    }
});

processes.add(new Consumer<Entity>() {
    @Override
    public void accept(Entity entity) {
        // Process second step.
    }
});

processes.add(new Consumer<Entity>() {
    @Override
    public void accept(Entity entity) {
        if (!(entity instanceof DerivedEntity)) {
            System.out.println("Step 3: The entity must be a DerivedEntity!");
            return;
        }
        // Process third step.
    }
});

Entity entity = new DerivedEntity();

for (Consumer<Entity> consumer : processes) {
    consumer.accept(entity);
}

答案 1 :(得分:1)

一个较小的更改只是将EntityStep上的类型变量声明简化为Entity而不是EntityStepInput

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

然后:

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) {}
}

它与以前完全相同,但是声明有点容易理解。

如果要使用某些特定的子类,则只需要T extends EntityStepInput<...>,但是由于您始终直接使用EntityStepInput,因此不需要。