Javagenerics – 太复杂了? 如何简化?
最初我在CodeReview上发布了这个问题,但这更适合StackOverflow。
我正在编写一个使用Java 6的多步骤过程。假设有3个步骤。
每个都接受相同类型的输入。 让我们开始。
这是作为输入传递给每个步骤的对象。 此对象充当另一类对象的包装器,以及一些步骤的共享值。 请注意,名称会被翻译为更通用的域名,而使用英语,原件是意大利语。
public class EntityStepInput { public final T entity; public boolean modified; public boolean canceled; public EntityStepInput(final T entity) { this.entity = entity; } }
这是每个步骤使用的接口。
public interface EntityStep<T extends EntityStepInput> { void process(final T stepInput) throws Exception; }
现在,3个步骤中的2个必须接受包含Entity
或从中派生的任何类型的EntityStepInput
。
public class FirstEntityStep implements EntityStep<EntityStepInput> { @Override public void process(final EntityStepInput stepInput) throws Exception {} } public class SecondEntityStep implements EntityStep<EntityStepInput> { @Override public void process(final EntityStepInput stepInput) throws Exception {} }
最后一步必须接受EntityStepInput
,其中包含从Entity
派生的特定类型。
public class ThirdEntityStep implements EntityStep<EntityStepInput> { @Override public void process(final EntityStepInput stepInput) throws Exception {} }
用法非常简单。 我有重载方法,接受不同类型的Entity
。 以下是简化版本。
public void workWithEntity(final DerivedEntity entity) throws Exception { final EntityStepInput stepInput = new EntityStepInput(entity); stepOne.process(stepInput); stepTwo.process(stepInput); stepThree.process(stepInput); }
如您所见, DerivedEntity
类型能够使用所有步骤。
public void workWithEntity(final OtherDerivedEntity entity) throws Exception { final EntityStepInput stepInput = new EntityStepInput(entity); stepOne.process(stepInput); stepTwo.process(stepInput); }
在这里,另一种类型的Entity
不能使用最后一步,这就是我想要的。
现在,这与generics变得相当复杂。 我担心在我离开之后谁会阅读我的代码将不会理解,迟早会发生混乱。
这可以简化吗? 您的方法将尽可能多地尊重单一责任原则?
编辑。 Entity
层次结构如下:
Entity > DerivedEntity Entity > OtherDerivedEntity
一个较小的更改只是将EntityStep
上的类型变量声明简化为Entity
而不是EntityStepInput
:
interface EntityStep { void process(EntityStepInput extends E> i); }
然后:
class FirstEntityStep implements EntityStep { @Override public void process(EntityStepInput extends Entity> i) {} } class SecondEntityStep implements EntityStep { @Override public void process(EntityStepInput extends Entity> i) {} } class ThirdEntityStep implements EntityStep { @Override public void process(EntityStepInput extends DerivedEntity> i) {} }
它和以前完全一样,但声明更容易理解。
如果你想使用某个特定的子类,你只需要T extends EntityStepInput<...>
,但由于你总是直接使用EntityStepInput
,所以你不需要它。
这是我第二次尝试回答。 我认为你目前使用的系统看起来不错; 它提供了编译时检查,因为您不希望允许步骤#3尝试处理任何不是DerivedEntity
(或其子项之一)的类型。
您可以使用List
来简化此操作List
List
,但是你失去了第3步的编译时类型检查,并被迫通过使用instanceof
改进它:
Java 8+解决方案:
List> 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 { void accept(T t); }
与上面相同的代码,但使用我们的Consumer
接口:
List> processes = new ArrayList>(); processes.add(new Consumer () { @Override public void accept(Entity entity) { // Process first step. } }); processes.add(new Consumer () { @Override public void accept(Entity entity) { // Process second step. } }); processes.add(new Consumer () { @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 consumer : processes) { consumer.accept(entity); }