英文:
Factory Method return Spring service
问题
我想要一个工厂类,它返回一个服务,我可以使用该服务进行一些验证。我实现了这个类。
public class EventUpdateValidatorFactory {
public EventUpdateValidatorStrategy getValidator(EEventStatus eventStatus) {
if (SECOND_APPROVAL.equals(eventStatus)) {
return new EventSecondApprovalValidator();
} else if (APPROVED.equals(eventStatus)) {
return new EventApprovedValidator();
} else if (ACCOUNTING_HQ.equals(eventStatus)) {
return new EventAccountingHqValidator();
}
throw new IllegalArgumentException("Unknown status");
}
}
接口 EventUpdateValidatorStrategy 如下:
public interface EventUpdateValidatorStrategy {
default <T extends EventUpdateValidatorStrategy> void validate(User user, EventMasterData masterData, Event event, List<EventExternalSystemExpenseSave> expenses,
List<EventExternalSystemSpeakerSave> speakers, long eventId) {
this.validateMasterData(masterData, event);
this.validateSpeakers(speakers, eventId);
this.validateExpenses(expenses, eventId);
this.doUpdate(user, masterData, expenses, speakers, eventId);
}
void validateMasterData(EventMasterData masterData, Event event);
void validateExpenses(List<EventExternalSystemExpenseSave> expenses, long eventId);
void validateSpeakers(List<EventExternalSystemSpeakerSave> speakers, long eventId);
void doUpdate(User user, EventMasterData masterData, List<EventExternalSystemExpenseSave> expenses, List<EventExternalSystemSpeakerSave> speakers, long eventId);
}
EventSecondApprovalValidator 的实现如下:
@Service
@Transactional
public class EventSecondApprovalValidator implements EventUpdateValidatorStrategy {
@Autowired
private EventService eventService;
@Autowired
private ContextDateService contextDateService;
@Autowired
private EventExpenseService eventExpenseService;
@Autowired
private EventExternalSystemDAO eventExternalSystemDAO;
@Override
public void validateMasterData(LocalEventMasterData masterData, Event event) {
// 一些逻辑
}
@Override
public void validateExpenses(List<EventExternalSystemExpenseSave> expenses, long eventId) {
// 一些逻辑
}
@Override
public void validateSpeakers(List<EventExternalSystemSpeakerSave> speakers, long eventId) {
// 一些逻辑
}
@Override
public void doUpdate(User user, EventMasterData masterData, List<EventExternalSystemExpenseSave> expenses, List<EventExternalSystemSpeakerSave> speakers, long eventId) {
ofNullable(expenses).ifPresent(expensesToSave -> expensesToSave.forEach(expense -> this.eventExternalSystemDAO.updateExpense(user, expense)));
this.eventExternalSystemDAO.updateEvent(user, masterData, eventId);
}
}
其他的 EventApprovedValidator 和 EventAccountingHqValidator 实现类似。
从主代码中,我进行以下调用:
final EventUpdateValidatorStrategy validator = EventUpdateValidatorFactory.getValidator(event.getStatus());
validator.validate(user, eventSave.getMasterData(), event, eventSave.getExpenses(), eventSave.getSpeakers(), eventID);
当我进入 EventSecondApprovalValidator 内部时,所有自动装配的服务都为 null,显然,我在第一次使用其中一个服务时会收到 NPE 错误。
我应该如何正确使用工厂根据 EEventStatus 返回所需的服务?
英文:
I want a factory class that return a service that I can use to do some validations. I implemented this class
public class EventUpdateValidatorFactory {
public EventUpdateValidatorStrategy getValidator(EEventStatus eventStatus) {
if (SECOND_APPROVAL.equals(eventStatus)) {
return new EventSecondApprovalValidator();
} else if (APPROVED.equals(eventStatus)) {
return new EventApprovedValidator();
} else if (ACCOUNTING_HQ.equals(eventStatus)) {
return new EventAccountingHqValidator();
}
throw new IllegalArgumentException("Unknown status");
}
}
The interface EventUpdateValidatorStrategy is this
public interface EventUpdateValidatorStrategy {
default <T extends EventUpdateValidatorStrategy> void validate(User user, EventMasterData masterData, Event event, List<EventExternalSystemExpenseSave> expenses,
List<EventExternalSystemSpeakerSave> speakers, long eventId) {
this.validateMasterData(masterData, event);
this.validateSpeakers(speakers, eventId);
this.validateExpenses(expenses, eventId);
this.doUpdate(user, masterData, expenses, speakers, eventId);
}
void validateMasterData(EventMasterData masterData, Event event);
void validateExpenses(List<EventExternalSystemExpenseSave> expenses, long eventId);
void validateSpeakers(List<EventExternalSystemSpeakerSave> speakers, long eventId);
void doUpdate(User user, EventMasterData masterData, List<EventExternalSystemExpenseSave> expenses, List<EventExternalSystemSpeakerSave> speakers, long eventId);
}
The EventSecondApprovalValidator is this
@Service
@Transactional
public class EventSecondApprovalValidator implements EventUpdateValidatorStrategy {
@Autowired
private EventService eventService;
@Autowired
private ContextDateService contextDateService;
@Autowired
private EventExpenseService eventExpenseService;
@Autowired
private EventExternalSystemDAO eventExternalSystemDAO;
@Override
public void validateMasterData(LocalEventMasterData masterData, Event event) {
// some logic
}
@Override
public void validateExpenses(List<EventExternalSystemExpenseSave> expenses, long eventId) {
// some logic
}
@Override
public void validateSpeakers(List<EventExternalSystemSpeakerSave> speakers, long eventId) {
// some logic
}
@Override
public void doUpdate(User user, EventMasterData masterData, List<EventExternalSystemExpenseSave> expenses, List<EventExternalSystemSpeakerSave> speakers, long eventId) {
ofNullable(expenses).ifPresent(expensesToSave -> expensesToSave.forEach(expense -> this.eventExternalSystemDAO.updateExpense(user, expense)));
this.eventExternalSystemDAO.updateEvent(user, masterData, eventId);
}
}
The other EventApprovedValidator and EventAccountingHqValidator implementations are similar.
From main code I do this call
final EventUpdateValidatorStrategy validator = EventUpdateValidatorFactory.getValidator(event.getStatus());
validator.validate(user, eventSave.getMasterData(), event, eventSave.getExpenses(), eventSave.getSpeakers(), eventID);
and the result is that when I enter inside a EventSecondApprovalValidator all the autowired services are null and, obviously, I receive a NPE the first time that I use one of that service.
How I correctly use the factory to return the service that I need based on EEventStatus?
答案1
得分: 2
在`EventUpdateValidatorFactory.getValidator(EEventStatus)`方法中,你需要从上下文中返回`EventSecondApprovalValidator` bean,而不是使用`new`关键字创建新的实例。
`EventSecondApprovalValidator`类被注解为`@Service`(假设只有一个这样的类型),这种类型的实例将由Spring添加到`ApplicationContext`中,并且会注入所有依赖关系。因此,只需从上下文中获取并使用它。
一种快速的方法如下:
```java
public EventUpdateValidatorStrategy getValidator(ApplicationContext context,
EEventStatus eventStatus) {
if (SECOND_APPROVAL.equals(eventStatus)) {
return context.getBean(EventSecondApprovalValidator.class);
} else if (APPROVED.equals(eventStatus)) {
return context.getBean(EventApprovedValidator.class);
} else if (ACCOUNTING_HQ.equals(eventStatus)) {
return context.getBean(EventAccountingHqValidator.class);
}
throw new IllegalArgumentException("Unknown status");
}
你还可以在EventUpdateValidatorFactory
中使用@Autowire
来自动注入所有验证器,并返回@Autowired
的实例。这将保持getValidator
方法的签名不变,但你需要将EventUpdateValidatorFactory
定义为类似于@Component
的类。
@Component
public class EventUpdateValidatorFactory {
@Autowired
EventSecondApprovalValidator a;
@Autowired
EventApprovedValidator b;
@Autowired
EventAccountingHqValidator c;
public EventUpdateValidatorStrategy getValidator(EEventStatus eventStatus) {
if (SECOND_APPROVAL.equals(eventStatus)) {
return a;
} else if (APPROVED.equals(eventStatus)) {
return b;
} else if (ACCOUNTING_HQ.equals(eventStatus)) {
return c;
}
throw new IllegalArgumentException("Unknown status");
}
}
<details>
<summary>英文:</summary>
In `EventUpdateValidatorFactory.getValidator(EEventStatus)` method, you need to return the `EventSecondApprovalValidator` bean from context, instead of creating a new instance using `new` keyword.
The class `EventSecondApprovalValidator` is `@Service` annotated (and assuming there is only one of this type), an instance of this type will be added to `ApplicationContext` by Spring with all dependencies injected. So, just fetch it from context and use it.
One quick way to do this is as follows:
public EventUpdateValidatorStrategy getValidator(ApplicationContext context,
EEventStatus eventStatus) {
if (SECOND_APPROVAL.equals(eventStatus)) {
return context.getBean(EventSecondApprovalValidator.class);
} else if (APPROVED.equals(eventStatus)) {
return context.getBean(EventApprovedValidator.class);
} else if (ACCOUNTING_HQ.equals(eventStatus)) {
return context.getBean(EventAccountingHqValidator.class);
}
throw new IllegalArgumentException("Unknown status");
}
You can also `@Autowire` all validators in `EventUpdateValidatorFactory` and return the `@Autowired` instances. This will keep the `getValidator` method's signature same, but you'll have to make `EventUpdateValidatorFactory` a `@Component`-esque class.
@Component
public class EventUpdateValidatorFactory {
@Autowired
EventSecondApprovalValidator a;
@Autowired
EventApprovedValidator b;
@Autowired
EventAccountingHqValidator c;
public EventUpdateValidatorStrategy getValidator(EEventStatus eventStatus) {
if (SECOND_APPROVAL.equals(eventStatus)) {
return a;
} else if (APPROVED.equals(eventStatus)) {
return b;
} else if (ACCOUNTING_HQ.equals(eventStatus)) {
return c;
}
throw new IllegalArgumentException("Unknown status");
}
</details>
# 答案2
**得分**: -2
```java
创建一个对象需要手动操作,这样就不会让 Spring 执行自动装配。考虑同时由 Spring 管理你的服务。
@Component
public class MyServiceAdapter implements MyService {
@Autowired
private MyServiceOne myServiceOne;
@Autowired
private MyServiceTwo myServiceTwo;
@Autowired
private MyServiceThree myServiceThree;
@Autowired
private MyServiceDefault myServiceDefault;
public boolean checkStatus(String service) {
service = service.toLowerCase();
if (service.equals("one")) {
return myServiceOne.checkStatus();
} else if (service.equals("two")) {
return myServiceTwo.checkStatus();
} else if (service.equals("three")) {
return myServiceThree.checkStatus();
} else {
return myServiceDefault.checkStatus();
}
}
}
英文:
Creating an object manually you are not letting Spring perform autowiring. Consider managing your services by Spring as well.
@Component
public class MyServiceAdapter implements MyService {
@Autowired
private MyServiceOne myServiceOne;
@Autowired
private MyServiceTwo myServiceTwo;
@Autowired
private MyServiceThree myServiceThree;
@Autowired
private MyServiceDefault myServiceDefault;
public boolean checkStatus(String service) {
service = service.toLowerCase();
if (service.equals("one")) {
return myServiceOne.checkStatus();
} else if (service.equals("two")) {
return myServiceTwo.checkStatus();
} else if (service.equals("three")) {
return myServiceThree.checkStatus();
} else {
return myServiceDefault.checkStatus();
}
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论