对于我的应用程序,我有一个Scale接口(interface)和多个实现此接口(interface)的类,例如NormalizedScaleLogScale等。在我的一个服务中,我需要创建许多Scales,并且我想使用Spring来定义Scale的哪个实现它应该创建。我将如何实现这样的事情?

--

我正在考虑创建一个工厂ScaleFactory,就像在“抽象工厂模式”中一样,我可以调用ScaleFactory.getScale()来获取我在Spring XML中配置的任何实现的Scale:

class ScaleFactory {
    Class<? extends Scale> scaleImplClass;
    public static Scale getScale() {
        return scaleImplClass.newInstance();
    }
}


Scale myScale = ScaleFactory.getScale();

但是使用这种方法,我如何配置ScaleFactory应该从Spring XML中使用哪种实现?

--

一种替代方法是使ScaleFactory成为@Service,然后将ScaleFactory自动连接到我的服务中:
@Autowired
ScaleFactory scaleFactory;

...

Scale myScale = scaleFactory.getScale();

然后,我可以使用ScaleFactory中的autowired属性来定义scaleImplClass。但这似乎很奇怪,因为我的工厂也是服务,而且我有该工厂的一个实例。

--

另一种方法是在我的服务中使用Class scaleImplementationClass属性而不是ScaleFacotry并使用ScaleFactory,如下所示:
@Value("${scaleImplementationClass}")
Class scaleImplementationClass

...

Scale myScale = ScaleFactory.getScale(scaleImplementationClass);

但是那时工厂是毫无意义的,因为我也可以运行scaleImplementationClass.newInstance()

最佳答案

有两种不同的类似Spring的方式可以处理此问题。我个人追求的方法看起来像这样:

public interface ScaleFactory {

    public Scale newInstance();
    public String type();

}

public class FirstScaleFactory implements ScaleFactory {

    public Scale newInstance() {
        return new FirstScale();
    }

    public String type() {
        return "first";
    }

}

public class SecondScaleFactory implements ScaleFactory {

    public Scale newInstance() {
        return new SecondScale();
    }

    public String type() {
        return "second";
    }

}

public class ScaleManager {

    private final Map<String, ScaleFactory> factories;

    @Autowired
    public ScaleManager(List<ScaleFactory> factories) {
        this.factories = factories.stream()
            .collect(Collectors.toMap(f -> f.type(), Function::identity));
    }

    public Scale newInstance(String type) {
        return Optional.ofNullable(factories.get(type))
            .map(factory -> factory.newInstance())
            .orElseThrow(IllegalArgumentException::new);
    }

}

通过这种方法,您的ScaleManager是标准的Spring bean,可以将其连接到任何需要scale实例的类中。在初始化时,它将获取在Spring上下文中定义的所有ScaleFactories,并将它们自动连接为List<ScaleFactory>,然后将其转换为Map(其中ScaleFactory类型为键)。这避免了您担心Scale的类名的麻烦,并使您能够在以后更改它们(只要保持type key 一致)。

然后,您的ScaleFactory实现可以执行所需的任何操作。例如,如果您知道一种不可变的Scale类型,则可以让工厂每次都返回相同的实例。另外,您可以让每个调用都返回一个单独的实例-Scale的实例取决于实现相关的工厂。

10-01 02:24