Заводской метод возврата Весенний сервис - PullRequest
0 голосов
/ 11 апреля 2020

Мне нужен фабричный класс, который возвращает сервис, который я могу использовать для проверки. Я реализовал этот класс

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) {
        // 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);
    }

}

Другие EventApprovedValidator и EventAccountingHqValidator реализации похожи.

Из основного кода я делаю этот вызов

final EventUpdateValidatorStrategy validator = EventUpdateValidatorFactory.getValidator(event.getStatus());
        validator.validate(user, eventSave.getMasterData(), event, eventSave.getExpenses(), eventSave.getSpeakers(), eventID);

, и в результате получается, что когда я вхожу внутрь EventSecondApprovalValidator , все службы с автоматической проводной связью становятся нулевыми, и, очевидно, я получаю NPE при первом использовании одной из этих служб.

Как правильно использовать фабрику для возврата необходимой мне услуги на основе EEventStatus ?

Ответы [ 2 ]

1 голос
/ 11 апреля 2020

В методе EventUpdateValidatorFactory.getValidator(EEventStatus) необходимо возвращать bean-компонент EventSecondApprovalValidator из контекста, а не создавать новый экземпляр с помощью ключевого слова new.

Класс EventSecondApprovalValidator является @Service аннотированным ( и предполагая, что есть только один из этого типа), экземпляр этого типа будет добавлен к ApplicationContext Spring со всеми введенными зависимостями. Итак, просто извлеките его из контекста и используйте его.

Один быстрый способ сделать это заключается в следующем:

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");
}

Вы также можете @Autowire все валидаторы в EventUpdateValidatorFactory и вернуть @Autowired экземпляров. Это сохранит сигнатуру метода getValidator такой же, но вы должны будете сделать EventUpdateValidatorFactory класс @Component -esque.

@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");
    }
0 голосов
/ 11 апреля 2020

Создавая объект вручную, вы не позволяете 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();
        }
    }
}
...