java - Java 泛型——太复杂了?如何简化?
问题描述
最初我在 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;
}
现在,3 个步骤中有 2 个必须接受一个EntityStepInput
包含 aEntity
或任何从它派生的类型。
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
s 的重载方法。以下是简化版。
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
解决方案
这是我第二次尝试回答。我认为您当前使用的系统看起来不错;它提供编译时检查,因为您不想让步骤 #3 尝试处理任何不是 a DerivedEntity
(或其子之一)的类型。
您可以通过使用 a 来简化此操作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);
}
推荐阅读
- java - How to calculate relative time spans using Java (code converting problem)?
- azure - 在 Windows 容器上运行的应用程序仅在启用 Hyper-V 容器的 SKU 中可用
- typescript - 如何在下一个导航中访问参数
- c++ - 如何在 C++ 类中实现 CreateThread - LPTHREAD_START_ROUTINE 类型的 ThreadProc 回调函数
- python - 根据列值对数据框进行排序
- javascript - 如何在不破坏 html 代码的情况下在 vuejs 模板中循环
- r - 如何从具有符号参数的函数的结果创建方程
- excel - 循环为每一行发送一封电子邮件
- node.js - 使用 axios 在 nodejs 中执行 post 请求,但我无法在 post 路由中接收数据
- javascript - 如何查找数组内的差异值并记录差异的索引