在Spring Boot中将子类分派到它们各自的执行器



这里是Java 11和Spring Boot(如果有区别的话)。我有以下pojo:

public abstract class AbstractFruit {
private String name;
private String description;
private Integer quantity;
// ...etc.
// getters, setters & ctor omitted for brevity
}
public class Apple extends AbstractFruit {
private AppleType appleType;
// etc.
}
public class Pear extends AbstractFruit { ... }
public class Orange extends AbstractFruit { ... }
// etc., dozens more

对于每个AbstractFruit子类,都有一个相应的AbstractFruitExecutor类执行该水果的实例:

public abstract class AbstractFruitExecutor<E extends AbstractFruit> {
protected abstract void execute(FruitProcessingContext fpc, E fruit);
// other stuff, omitted for brevity
}
public class AppleExecutor extends AbstractFruitExecutor<Apple> { ... }
public class PearExecutor extends AbstractFruitExecutor<Pear> { ... }
public class OrangeExecutor extends AbstractFruitExecutor<Orange> { ... }

我将得到一个List<AbstractFruit>,需要将列表中的每个元素发送到其各自的执行器:

@Service
public class FruitExecutionDispatch {
@Autowired
private Map<Class<? extends AbstractFruit>, AbstractFruitExecutor> fruitExecutorMap;
public void executeAll(List<AbstractFruit> fruits, FruitProcessingContext fpc) {
fruits.forEach(fruit -> {
AbstractFruitExecutor<?> fruitExecutor = findFruitExecutor(fruit).orElseThrow();
fruitExecutor.execute(fpc, fruit);
});
}
private Optional<AbstractFruitExecutor<?>> findFruitExecutor(AbstractFruit fruit) {
return Optional.ofNullable(fruitExecutorMap.get(fruit.getClass()));
}
}

不幸的是,上面的代码产生了一个编译错误:

">所需类型:捕获?,提供:AbstractFruit">

以上是IntelliJ IDE错误。在命令行上,当我尝试运行应用程序时,我得到:

where CAP#1 is a fresh type-variable:
CAP#1 extends AbstractFruit from capture of ?

有人能发现我在哪里走错了,并解释我如何修复这个编译器错误?此外,如果Spring/Boot提供了更好的设计模式或实用程序来帮助解决这个问题,我将洗耳恭听。提前感谢!

编译器错误是由于fruitExecutorMap字段被定义为可以保存任何AbstractFruitExecutor实例的Map而引起的。当调用fruitExecutorMap.get(fruit.getClass())时,返回的值是扩展了AbstractFruit的未知类型,从而导致兼容性问题。要解决这个问题,可以为fruitExecutorMap字段使用有界通配符,只接受可以处理AbstractFruit的特定子类型的AbstractFruitExecutor实例。这保证了fruitExecutor类型和fruit类型之间的兼容性,从而解决了错误。

private Map<Class<? extends AbstractFruit>, AbstractFruitExecutor<? extends AbstractFruit>> fruitExecutorMap;
另一个解决方案是使用访问者设计模式
public interface FruitVisitor {
void visit(Apple apple);
void visit(Pear pear);
void visit(Orange orange);
// Add visit methods for other concrete subclasses of AbstractFruit as needed
}
public abstract class AbstractFruit {
// ...
public abstract void accept(FruitVisitor visitor);
}
public class Apple extends AbstractFruit {
// ...
@Override
public void accept(FruitVisitor visitor) {
visitor.visit(this);
}
}
public class Pear extends AbstractFruit {
// ...
@Override
public void accept(FruitVisitor visitor) {
visitor.visit(this);
}
}
public class Orange extends AbstractFruit {
// ...
@Override
public void accept(FruitVisitor visitor) {
visitor.visit(this);
}
}
public class FruitProcessingContext {
// Define any context information needed for fruit processing
}
@Service
public class FruitExecutionDispatch implements FruitVisitor {
@Autowired
private FruitProcessingContext fpc;
public void executeAll(List<AbstractFruit> fruits) {
fruits.forEach(fruit -> fruit.accept(this));
}
@Override
public void visit(Apple apple) {
// Logic for processing an apple goes here
}
@Override
public void visit(Pear pear) {
// Logic for processing a pear goes here
}
@Override
public void visit(Orange orange) {
// Logic for processing an orange goes here
}
// Implement additional visit methods for other concrete subclasses of AbstractFruit as needed
}

最新更新