工厂方法返回Spring服务

huangapple go评论71阅读模式
英文:

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

其他的 EventApprovedValidatorEventAccountingHqValidator 实现类似。

从主代码中,我进行以下调用:

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(&quot;Unknown status&quot;);
    }
}

The interface EventUpdateValidatorStrategy is this

public interface EventUpdateValidatorStrategy {

	default &lt;T extends EventUpdateValidatorStrategy&gt; void validate(User user, EventMasterData masterData, Event event, List&lt;EventExternalSystemExpenseSave&gt; expenses,
			List&lt;EventExternalSystemSpeakerSave&gt; 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&lt;EventExternalSystemExpenseSave&gt; expenses, long eventId);
	void validateSpeakers(List&lt;EventExternalSystemSpeakerSave&gt; speakers, long eventId);
	void doUpdate(User user, EventMasterData masterData, List&lt;EventExternalSystemExpenseSave&gt; expenses, List&lt;EventExternalSystemSpeakerSave&gt; 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&lt;EventExternalSystemExpenseSave&gt; expenses, long eventId) {
		// some logic
	}

	@Override
	public void validateSpeakers(List&lt;EventExternalSystemSpeakerSave&gt; speakers, long eventId) {
		// some logic
	}

	@Override
	public void doUpdate(User user, EventMasterData masterData, List&lt;EventExternalSystemExpenseSave&gt; expenses, List&lt;EventExternalSystemSpeakerSave&gt; speakers, long eventId) {
		ofNullable(expenses).ifPresent(expensesToSave -&gt; expensesToSave.forEach(expense -&gt; 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(&quot;Unknown status&quot;);
    }



You can also `@Autowire` all validators in `EventUpdateValidatorFactory` and return the `@Autowired` instances. This will keep the `getValidator` method&#39;s signature same, but you&#39;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(&quot;Unknown status&quot;);
        }


</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(&quot;one&quot;)) {
            return myServiceOne.checkStatus();
        } else if (service.equals(&quot;two&quot;)) {
            return myServiceTwo.checkStatus();
        } else if (service.equals(&quot;three&quot;)) {
            return myServiceThree.checkStatus();
        } else {
            return myServiceDefault.checkStatus();
        }
    }
}

huangapple
  • 本文由 发表于 2020年4月11日 06:14:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/61149456.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定