对于我的应用程序,我有一个Scale
接口(interface)和多个实现此接口(interface)的类,例如NormalizedScale
,LogScale
等。在我的一个服务中,我需要创建许多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
的实例取决于实现相关的工厂。