【问题标题】:Is it bad practice to use dependency injection in factory classes?在工厂类中使用依赖注入是不好的做法吗?
【发布时间】:2018-07-01 05:37:51
【问题描述】:

在工厂类中使用依赖注入是不好的做法吗?我应该让我的框架的用户处理依赖注入吗?我应该使用方法 A 还是方法 B?

SomeUserClass

package com.impl;

@Service
public class SomeUserClass {

    @Autowired
    private SMSActionFactoryService actionFactoryService:

    @Autowired
    private PropertyManager properties;

    public void doStuff(){
        // approach A
        SMSAction action = actionFactoryService.createAction("hello");

        // approach B
        action = SMSActionFactory.createAction(properties, "hello");

        // the user should never call Action::doAction. 
        // It gets called by the framework on a condition.
        scheduler.addAction(State.ERROR, action)
    }

}

短信操作

package com.framework;

public class SMSAction extends Action {

    public SMSAction(PropertyManager properties, String message){

    }

    public void doAction(){
    }

}

SMSActionFactoryService

package com.framework;

@Service
public class SMSActionFactoryService {

    @Autowired
    private PropertyManager properties;

    public SMSActionFactory createAction(String message) {
        return new SMSActionFactoryService(properties, message);
    }
}

短信操作工厂

package com.framework;

public class SMSActionFactory {

    public static SMSActionFactory createAction(PropertyManager properties, String message) {
        return new SMSActionFactory(properties, message);
    }
}

【问题讨论】:

  • 方法 A 使单元测试变得容易。方法 B 使单元测试变得痛苦。避免痛苦! (并遵循 TDD 或至少在不久之后编写单元测试以快速发现代码异味。)

标签: java spring factory-pattern


【解决方案1】:

我认为你有一个上下文问题,所以答案取决于上下文。但我会给出一些我的经验,而不是一个正式的(和无可辩驳的)答案。根据答案的标题(实践),我将为您提供我所谓的良好实践提示,这些提示在我开始 Spring 开发时对我有很大帮助。

首先,让我们考虑一下您拥有的依赖注入。您正在连接一个字段,我们知道 Spring 团队曾经建议我们使用基于构造函数的注入(以及所有强制依赖项的断言),如您所见 here。好吧,我知道测试框架存在问题,无法以简单的方式连接依赖项,但现在他们可以了。但是使用这种模式还有另一个好处,你可以让你的bean字段final。另一个优点是您可以防止循环依赖,例如 X 依赖于 Y 和 Y 依赖于 X 等等。所以,作为第一个提示,我建议你使用类似的东西:

private final SMSActionFactoryService actionFactoryService:
private final PropertyManager properties;

@Autowired
public SomeUserClass(SMSActionFactoryService actionFactoryService,
                     PropertyManager properties) {
     Assert.notNull(actionFactoryService, "The actionFactoryService bean is null, you should provide the bean to run this application");
     Assert.notNull(properties, "The properties bean is null, you should provide the bean to run this application");

     this.actionFactoryService = actionFactoryService;
     this.properties = properties;
}

这样可以防止任何其他代码部分更改字段值。正如您在Spring autowiring setter/constructor PROs and CONs 中看到的,这是一个偏好主题。

现在,对于第二个提示,我不会将 @Service 用于工厂,甚至不会使用 @Component,因为工厂需要打开以进行扩展并关闭以进行修改。看看here你会更明白。

那位朋友,我建议你接受方法B

【讨论】:

  • SomeUserClass 不是框架的一部分,它只是一个实现示例。有不同的 ActionFactory 类,所以我不能只将工厂传递给用户。用户必须了解不同的 ActionFactory 类并自己注入它们。
  • 好吧,我可以添加一个可以创建所有不同动作的 ActionFactoryGodClass,但我认为这不是一个好方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-04
  • 1970-01-01
  • 1970-01-01
  • 2012-08-09
  • 1970-01-01
  • 2021-01-25
  • 1970-01-01
相关资源
最近更新 更多