如何在命令设计模式实现中为命令类注入Repository?
问题背景
我有几个类中存在相似的else if语句,打算使用命令模式对其进行替换。核心思路是将else if的执行逻辑抽离外置,根据调用服务的不同使用对应的Repository完成操作。但我目前找不到将Repository注入到命令类的可行方式,以下通过示例详细说明:
待改造代码片段
private HashMap<String, BnResponseHandler> commandMap = new HashMap<>(); for (CustomerDelivery customerDelivery : list) { commandMap.put("true", new SuccessfulResponse(customerDelivery)); commandMap.put("1", new ResponseCodeOne(customerDelivery)); commandMap.put("2", new ResponseCodeTwo(customerDelivery)); commandMap.put("3", new ResponseCodeThree(customerDelivery)); BnResponseHandler bnResponseHandler = new DefaultHandler(customerDelivery); if(response.isSuccessful()){ commandMap.get(String.valueOf(response.isSuccessful())).handle(); } else if (response.getResponseCode() != null && !response.getResponseCode().equals("")){ commandMap.get(response.getResponseCode()).handle(); } else { bnResponseHandler.handle(); } }
定义的公共接口
public interface BnResponseHandler { void handle(); }
接口实现类示例
@Component public class ResponseCodeOne implements BnResponseHandler { @Autowired private FabricationRepository fabricationRepo; private Fabrication fabrication; @Autowired private MovementsRepository movementsRepository; private StockMovements stockMovements; @Autowired private CustomerDeliveryRepository customerDeliveryRepo; private CustomerDelivery customerDelivery; public ResponseCodeOne() { } public ResponseCodeOne(Fabrication fabrication) { this.fabrication = fabrication; } public ResponseCodeOne(StockMovements stockMovements) { this.stockMovements = stockMovements; } public ResponseCodeOne(CustomerDelivery customerDelivery) { this.customerDelivery = customerDelivery; } @Override public void handle() { if (fabrication != null) { fabrication.setFG_ETAT("D"); fabrication.setLB_ETAT(""); fabricationRepo.save(fabrication); } else if (stockMovements != null) { stockMovements.setFG_ETAT("D"); stockMovements.setLB_ETAT(""); movementsRepository.save(stockMovements); } else if (customerDelivery != null) { customerDelivery.setFG_ETAT("D"); customerDelivery.setLB_ETAT(""); customerDeliveryRepo.save(customerDelivery); } } }
我的整体设计思路是:为所有可能接收到的响应码(本示例中为1)分别定义对应的ResponseCode处理类,在类内部实现依赖Repository Bean的业务逻辑,同时要保证灵活性,使ResponseCodeOne这类处理类可支持多种不同业务场景(即可适配Fabrication、StockMovements、CustomerDelivery三类实体)。目前遇到的问题是按上述方式实现后,Repository无法成功注入,持续抛出空指针异常。请问是否有简洁优雅的方式可以实现Repository Bean的注入?
根因分析
手动通过new关键字创建ResponseCodeOne等标注了@Component的类实例,这些实例不归Spring IoC容器管理,Spring不会自动注入@Autowired声明的Repository依赖,导致调用时触发空指针异常。
最优解决方案
推荐将业务参数和处理器逻辑拆分,处理器保持Spring单例管理,无需每次循环创建实例,性能和可维护性更好:
1. 改造公共接口
增加泛型支持,将业务实体作为handle方法的入参:
public interface BnResponseHandler<T> { void handle(T entity); }
2. 改造处理器实现类
移除实体成员变量,直接在handle方法中接收参数,Repository可正常被Spring注入:
@Component public class ResponseCodeOne implements BnResponseHandler<Object> { // 若三个实体有公共父类/接口,可替换Object为公共类型进一步优化 @Autowired private FabricationRepository fabricationRepo; @Autowired private MovementsRepository movementsRepository; @Autowired private CustomerDeliveryRepository customerDeliveryRepo; @Override public void handle(Object entity) { if (entity instanceof Fabrication fabrication) { fabrication.setFG_ETAT("D"); fabrication.setLB_ETAT(""); fabricationRepo.save(fabrication); } else if (entity instanceof StockMovements stockMovements) { stockMovements.setFG_ETAT("D"); stockMovements.setLB_ETAT(""); movementsRepository.save(stockMovements); } else if (entity instanceof CustomerDelivery customerDelivery) { customerDelivery.setFG_ETAT("D"); customerDelivery.setLB_ETAT(""); customerDeliveryRepo.save(customerDelivery); } } }
3. 改造业务调用逻辑
仅初始化一次命令映射表,无需每次循环重复创建实例和赋值:
// 注入所有Spring管理的处理器实例 @Autowired private SuccessfulResponse successfulResponse; @Autowired private ResponseCodeOne responseCodeOne; @Autowired private ResponseCodeTwo responseCodeTwo; @Autowired private ResponseCodeThree responseCodeThree; @Autowired private DefaultHandler defaultHandler; private HashMap<String, BnResponseHandler<?>> commandMap = new HashMap<>(); // 类初始化时仅构建一次命令映射 @PostConstruct public void initCommandMap() { commandMap.put("true", successfulResponse); commandMap.put("1", responseCodeOne); commandMap.put("2", responseCodeTwo); commandMap.put("3", responseCodeThree); } // 业务循环逻辑 public void processList(List<CustomerDelivery> list, Response response) { for (CustomerDelivery customerDelivery : list) { BnResponseHandler<?> handler; if(response.isSuccessful()){ handler = commandMap.get(String.valueOf(response.isSuccessful())); } else if (response.getResponseCode() != null && !response.getResponseCode().isBlank()){ handler = commandMap.get(response.getResponseCode()); } else { handler = defaultHandler; } handler.handle(customerDelivery); } }
备选方案(保留原Handler带实体成员的写法)
如果不想调整原有结构,可将处理器改为原型作用域,通过Spring上下文获取实例:
- 给所有处理器类增加原型作用域注解:
@Component @Scope("prototype") public class ResponseCodeOne implements BnResponseHandler { // 原有代码不变 }
- 注入Spring上下文,通过上下文获取实例:
@Autowired private ApplicationContext applicationContext; // 循环中获取实例的代码改为 ResponseCodeOne handler = applicationContext.getBean(ResponseCodeOne.class, customerDelivery);
内容的提问来源于stack exchange,提问作者aratata
相关产品推荐
相关产品推荐

