这更像是一个设计问题,而不是代码实现,但我希望有人可以提供帮助。
我面临的问题是我需要根据两个输入注入一个modelSerivce。我非常肯定基于一些文档和SO问题,我想为此使用一个factorybean。
我的问题更多地涉及将使用factorybean创建的这些类的构造。如何在工厂中重复使用单件bean而不是每次调用工厂时创建一个新类?
代码如下所示:
事物接口:
public interface Thing {
void Run();
}
ThingA实施:
public class ThingA implements Thing{
public void Run() {
System.out.println("In ThingA");
}
}
ThingB实施:
public class ThingB implements Thing{
public void Run() {
System.out.println("In ThingB");
}
}
ThingFactory实施:
public class ThingFactory {
public Thing GetThing(String stateCode, Date date){
Thing result;
if(stateCode == "MA") {
result = new ThingA();
}
else {
result = new ThingB();
}
return result;
}
}
我真正希望工厂做的是拉出一个已知的实现,而不是每次调用工厂时创建一个实现。我也想通过这样的方式将我的工厂绑定到Spring框架:
ApplicationContext.getBean()
答案 0 :(得分:2)
实际上我处理了同样的问题,这是我提出的解决方案。我所依赖的主要技巧是,任何定义为单线程的bean都是在Spring初始化时由Spring实现的。所以这就是我所做的:
ThingImpl
的抽象类Thing
界面,将成为您所有ThnigA
,ThingB
...类的父级。 (或者只是将您的Thing
界面更改为抽象类)将您的ThingFactory
更改为以下内容:
public class ThingFactory {
private static Map<String, Thing> instancesMap = new Hashmap<>()
public static Thing getThing(String name) {
return instancesMap.get(name);
}
public static addInstance(String name, Thing thing) {
instancesMap.put(name, thing);
}
}
在您的抽象父级中添加以下构造函数
public ThingImpl() {
ThingFactory.addInstance(this.getClass().getSimpleName(), this);
}
您的工厂根本不需要定义为bean,但所有Thing
类都应定义为bean。将要发生的事情是,当Spring初始化时,它将实例化所有Thing
类,并且作为其自身初始化的一部分,每个Thing
类将自己插入到工厂的地图中。因此,您现在需要做的就是在您的代码中的任何地方,您可以致电您的工厂:
ThingFactory.getThing("ThingA");
ThingFactory.getThing("ThingB");
答案 1 :(得分:1)
只需像往常一样将bean作为单例保留在spring环境中。将上下文注入工厂并根据业务规则从中提取bean。
public class ThingFactory {
@Autowired
private ApplicationContext ctx;
public Thing GetThing(String stateCode, Date date){
Thing result;
if(stateCode == "MA") {
result = ctx.getBean("someBean")
}
else {
result = ctx.getBean("someOtherBean")
}
return result;
}
}
您可以更聪明,并使用方案在上下文中命名bean:
@Service("Thing_MA")
public class ThingA implements Thing{
.
.
.
}
这为您的工厂购买了很好的声明式查找规则:
public class ThingFactory {
public Thing GetThing(String stateCode, Date date){
return (Thing) ctx.getBean("Thing_" + stateCode);
}
}
答案 2 :(得分:0)
如果您不想绑定代码弹簧框架,则意味着您不想BeanFactory
并创建自己的工厂,那么您必须自己创建对象
public class ThingFactory {
private final static Thing thingA = new ThingA();
private final static Thing thingB = new ThingB();
public Thing GetThing(String stateCode, Date date){
if(stateCode.equals("MA")) {
return thingA;
} else {
return thingB;
}
}
}
如果你在这种情况下有更多Thing
的实现,你只需创建一个地图并根据需要获取对象。
public class ThingFactory {
private final static Map<String, Thing> beanMap = new Hashmap<>()
public ThingFactory(){
addThing("ThingA", new ThingA());
addThing("ThingB", new ThingB());
}
public static Thing getThing(String name) {
return beanMap.get(name);
}
public static addThing(String name, Thing thing) {
beanMap.put(name, thing);
}
public Thing GetThing(String stateCode, Date date){
if(stateCode.equals("MA")) {
return getThing("ThingA");
} else {
return getThing("ThingB");
}
}
}
但是,我建议你选择Spring BeanFactory
而不是创建自己的工厂,然后选择@Robert Moskal回答。
如果在应用程序启动时知道stateCode
的值,您可以使用spring profiles
来实现此目的。
@Service
@Profile("ThingB")
public class ThingB implements Thing{
public void Run() {
System.out.println("In ThingB");
}
}