我已经创建了下面提到的基类和派生类
public abstract class ContextBase {
private String customerID;
private String marketplaceID;
}
public class ReturnContext extends ContextBase {
private String returnID;
}
然后我创建了一个接口,它有一个名为perform的方法和一些实现这个接口的类
public interface ValidatorInterface<T extends ContextBase> {
CompletableFuture<List<String>> perform(T context);
}
public class AlphaValidator implements ValidatorInterface<ContextBase> {
@Override
public CompletableFuture<List<String>> perform(ContextBase contextBase) {
....
}
}
public class BetaValidator implements ValidatorInterface<ReturnContext> {
@Override
public CompletableFuture<List<String>> perform(ReturnContext context) {
....
}
}
我想运行一个并行实现ValidatorInterface的类列表,所以我创建了一个ValidatorRunner类
public class ValidatorRunner<T extends ContextBase> {
public List<String> runValidators(final T context,
final List<ValidatorInterface<T>> validatorsList) {
final Map<String, CompletableFuture<List<String>>> futureAggregatedProblems = new LinkedHashMap<>(validatorsList.size());
List<String> problems = new ArrayList<>();
validatorsList.forEach(validator -> runValidator(
validator, futureAggregatedProblems, context));
futureAggregatedProblems.forEach((validatorName, futureProblems) -> {
try {
problems.addAll(futureProblems.get(FUTURE_TIMEOUT_MS, TimeUnit.MILLISECONDS));
} catch (InterruptedException | ExecutionException | CompletionException | TimeoutException ex) {
// TODO Do not ignore InterruptedException
throw new InternalServiceException("Error executing validators : " + ex.getMessage(), ex);
}
});
return problems;
}
private void runValidator(final ValidatorInterface<T> validator,
final Map<String, CompletableFuture<List<String>>> futureAggregatedProblems,
final T context) {
futureAggregatedProblems.put(validator.getClass().getCanonicalName(), validator.perform(context));
}
当我执行
时,这个实现似乎有效ValidatorRunner<ReturnContext> validatorRunner = new ValidatorRunner<ReturnContext>();
ReturnContext context = new ReturnContext();
BetaValidator beta = new BetaValidator();
List<ValidatorInterface<ReturnContext>> validatorList = new ArrayList<>();
validatorList.add(beta);
List<String> problems = validatorRunner.runValidators(context, validatorList);
问题是AlphaValidator是在基类型(ContextBase)上实现的,而BetaValidator是在派生类型(ReturnContext)上实现的。我想并行运行AlphaValidator和BetaValidator,同时传递ReturnContext的实例作为上下文。如何实现?
编辑1
我将ValidatorInterface创建为T的原因扩展了ContextBase因为我希望每个验证器要么使用一个ContextBase,要么使用一个ContextBase的派生类。
我已经在基础类型ContextBase上创建了AlphaValidator,因为我希望使用ContextBase的任何派生类来创建和执行AlphaValidator。而BetaValidator是在ReturnContext上创建的,因为我想只使用ReturnContext创建和执行BetaValidator。假设我创建了一个名为ReplacementContext的新派生类,它扩展了ContextBase,并在派生类型ReplacementContext上创建了一个名为GammaValidator的新验证器。我想能够运行AlphaValidator和GammaValidator使用ReplacementContext。AlphaValidator和BetaValidator应该在ReturnContext上运行。但是我不想并行运行BetaValidator和GammaValidator,因为它们服务于不同的目的和单独的上下文(这就是为什么它们分别在单独的上下文中创建,分别为ReturnContext和ReplacementContext)。
上面代码的问题
当为多个验证器提供单个具体上下文时,每个验证器必须支持给定的上下文类。这是设计问题。
我的解决方案另一种解决方案是为runValidate
方法提供多个上下文,其中每个上下文都可以放置在正确的验证器旁边。
在我的例子中,ContextProcessor.of()
会注意编译器只允许验证器和上下文的正确赋值。
我建议将您的ValidatorRunner
更改为与此代码类似的版本:
public class ValidatorRunner {
static class ContextProcessor<T extends ContextBase> {
private final List<ValidatorInterface<T>> validators;
private final T context;
private ContextProcessor(List<ValidatorInterface<T>> validators, T context) {
this.validators = validators;
this.context = context;
}
public static <V extends ValidatorInterface<C>, C extends ContextBase> ContextProcessor<C> of(List<V> validators, C context) {
//noinspection unchecked
return new ContextProcessor<>((List<ValidatorInterface<C>>) validators, context);
}
public List<ValidatorInterface<T>> getValidators() {
return validators;
}
public T getContext() {
return context;
}
}
public List<String> runValidators(final List<ContextProcessor<? extends ContextBase>> processors) {
var validators = processors.stream().map(p -> p.validators.size()).reduce(Integer::sum).orElse(0);
var latch = new CountDownLatch(validators);
var problemStack = new ArrayList<String>();
//noinspection unchecked
processors.forEach(p -> p.getValidators().forEach(validator ->
runValidator((ValidatorInterface<ContextBase>) validator, p.getContext())
.orTimeout(10_000L, TimeUnit.MILLISECONDS)
.thenAccept(problems -> {
problemStack.addAll(problems);
latch.countDown();
})
));
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return problemStack;
}
private CompletableFuture<List<String>> runValidator(final ValidatorInterface<ContextBase> validator, final ContextBase context) {
return validator.perform(context);
}
public static void main(String[] args) {
var problems = new ValidatorRunner().runValidators(
List.of(
ContextProcessor.of(List.of(new AlphaValidator(), new AlphaValidator()), new ReplacementContext()),
ContextProcessor.of(List.of(new AlphaValidator()), new ContextBase() {}),
ContextProcessor.of(List.of(new BetaValidator(), new BetaValidator()), new ReturnContext())
)
);
System.out.println(problems);
}
}
当运行提供的main
方法时,期望得到以下结果:
[error within context ReplacementContext, error within context ReplacementContext, error within context , error within context ReturnContext, error within context ReturnContext]
每个验证器都返回Future
字符串"error within context" + context.getClass().getSimpleName()
也许这会帮助你找到解决问题的方法。