如何从singleton生成原型对象? (需要设计帮助)

时间:2011-05-26 09:17:27

标签: spring design-patterns scope

我对春天比较陌生,我自己挖了个洞。我正在试图塑造汽车。每个模型都有自己的构建器对象,我有一个BuilderFactory,它根据用户从web-app中选择返回正确的构建器。

所以我正在寻找有关如何解决这个问题的建议,我需要创建一些单独的车辆,但我不知道在运行时我需要什么类型的车辆,每个车辆必须是用户独有的。

目前我得到的内容如下所示。我现在面临的问题是,因为个别建筑商都是单身人士,所以个别车辆也是如此。我需要他们 成为原型。我知道这一切看起来都非常糟糕,所以我相信一定有更好的办法。

网络应用程序的顶级显示;

Vehicle vehicle = vehicleBuilderFactory.getBuilder(platform).build();

我的vehicleBuilderFactory看起来像这样;

@Service
public class VehicleBuilderFactory {

@Autowired
Discovery3Builder discovery3Builder;
@Autowired
Discovery4Builder discovery4Builder;

    // Lots of @Autowired statements here. 

@Autowired
FreeLander2010Builder freeLander2010Builder;



public VehicleBuilder getBuilder(Platform platform) {

    switch (platform.getId()) {

    case 1: return discovery3Builder;
    case 2: return discovery4Builder;

            // Lots of case statements here

            case 44: return freeLander2010Builder;
    default: return null;
    }
}

}

本身看起来非常可怕。每个单独的构建器看起来像;

@Service
public class DefenderBuilder implements VehicleBuilder {

@Autowired
Defender defender;

// Loads of Defender specific setters ommitted  
@Override
public Vehicle build() {
    return defender;
}

}

最后是个别车辆

@Service
@Scope("prototype")
public class Defender extends Vehicle {

}

现在的主要问题是,因为建造者是单身人士,所以车辆也是如此 我需要它们作为原型,因为用户A的后卫与用户B的后卫不同。

3 个答案:

答案 0 :(得分:12)

你可以使用Spring的ObjectFactory让它从单例作用域bean中提供原型作用域bean。用法非常简单:

@Component
class DefenderBuilder implement VechicleBuilder {

  @Autowired
  ObjectFactory<Defender> defenderFactory;

  Defender build() {
     return defenderFactory.getObject()
  }
}

@Component
@Scope("prototype")
class Defender {

}

每次调用defenderFactory.getObject()

时都会返回一个新的Defender

答案 1 :(得分:0)

如果没有详细阅读细节,你说你想从单例中生成Prototype bean,可能需要在IoC容器中查找。

第3.4.6.1节查询方法注入Spring documentation描述了如何在不丢失控制反转的情况下完成此操作,即不让bean知道bean存储。

我之前使用ServiceLocatorFactoryBean解决了类似的问题。类级Javadoc非常好,包含一些明确的例子。

答案 2 :(得分:0)

两件事: 1)您可以使用代理来容纳范围更广的范围更窄的范围(例如,单例的原型) 您所需要做的就是使用相关范围和proxyMode定义原型组件。 您可以阅读有关作用域代理here的信息。

2)我注意到的另一件事是,您计划使用多个自动装配注释。 请注意,您可以在接口列表上使用自动装配,它将自动装配实现该接口的所有组件,如here所述。

此外,您可以将平台ID添加到VehicleBuilder接口,然后在构造函数中生成地图,例如:

Map<Integer, VehicleBuilder> vehicleBuilders;
@Autowired
public VehicleBuilderFactory(List<VehicleBuilder> vehicleBuilders) {
   this.vehicleBuilders = vehicleBuilders.stream()
        .collect(Collectors(x -> x.getPlatformId(), x -> x));
}

通过这种方式,您可以避免出现这种情况。