我有ProductHandler
类具有不同的实现,例如ABCProductHandler
,DEFProductHandler
等。这些是使用命令模式从ProductServiceImpl
类中调用的如modern replacements所示。
ProductServiceImpl类:
@Service
public class ProductServiceImpl implements ProductService {
private Map<ProductType,ProductHandler> productHandlersMap =
new EnumMap<>(ProductType.class);
private ABCProductHandler abcProductHandler;
private DEFProductHandler defProductHandler;
//....10 other product handlers goes here
@Autowired
public ProductServiceImpl(ABCProductHandler abcProductHandler,
DEFProductHandler defProductHandler, .....) {
this.abcProductHandler = abcProductHandler;
this.defProductHandler = defProductHandler;
//....10 other product handlers goes here
}
@PostConstruct()
public void init() {
productHandlersMap.put(ProductType.ABC, abcProductHandler);
productHandlersMap.put(ProductType.DEF, defProductHandler);
//....10 other product handlers goes here
}
@Override
public ProductDetails calculateProductPrice(ProductType productType) {
productHandlersMap.get(productType).calculate();
//..some otehr code goes here
return productDetails;
}
}
但是,我对上面的ProductServiceImpl
类不满意,因为有许多带有样板代码的productHandlersMap.put
调用。
现在,我的问题是,有什么方法可以轻松加载productHandlersMap
?
@Service
public class ProductServiceImpl implements ProductService {
private Map<ProductType,ProductHandler> productHandlersMap =
new EnumMap<>(ProductType.class);
@PostConstruct()
public void init() {
//How to laod productHandlersMap easily with
// different ProductHandler types here?
}
@Override
public ProductDetails calculateProductPrice(ProductType productType) {
productHandlersMap.get(productType).calculate();
//..some other code goes here
return productDetails;
}
}
答案 0 :(得分:2)
Spring可以自动将实施接口I
的bean的不同实现自动连接到类型为Map<String, I>
的属性,其中键是bean的 name 和重视bean实例。由于您已经有一个针对每个ProductHandler
实现的枚举,因此可以利用它:
public enum ProductType {
ABC(ProductType.ABC_BEAN_NAME),
DEF(ProductType.DEF_BEAN_NAME);
public static final String ABC_BEAN_NAME = "abcProductHandler";
public static final String DEF_BEAN_NAME = "defProductHandler";
private String beanName;
ProductType(String beanName) { this.beanName = beanName; }
public String beanName() { return beanName; }
}
然后,在ProductHandler
工厂类中或通过@Configuration
或@Service
批注定义不同的@Component
实现:
@Service(ProductType.ABC_BEAN_NAME)
public class ABCProductHandler implements ProductHandler {
// ...
}
@Service(ProductType.DEF_BEAN_NAME)
public class DEFProductHandler implements ProductHandler {
// ...
}
现在,在您的ProductServiceImpl
bean中,只需自动连接Map<String, ProductHandler>
:
@Service
public class ProductServiceImpl implements ProductService {
private final Map<String, ProductHandler> productHandlersMap;
@Autowired
public ProductServiceImpl(Map<String, ProductHandler> productHandlersMap) {
this.productHandlersMap = productHandlersMap;
}
@Override
public ProductDetails calculateProductPrice(ProductType productType) {
productHandlersMap.get(productType.beanName()).calculate();
//..some otehr code goes here
return productDetails;
}
}
这样,您就可以让Spring完成所有的注入工作,甚至不需要使用@PostConstruct
方法。
请注意在productType.beanName()
方法内使用calculateProductPrice
。这样可以确保您使用正确的bean来计算价格。
答案 1 :(得分:1)
您可以创建spring配置组件
@Configuration
public class CollectionConfig {
@Bean
public ProductHandler getABC() {
return new ABCProductHandler(ProductType.ABC);
}
@Bean
public ProductHandler getDEF() {
return new DEFProductHandler(ProductType.DEF);
}
@Bean
public ProductHandler getXYZ() {
return new XYZProductHandler(ProductType.XYZ);
}
// other factory methods
}
然后:
@Service
public class ProductServiceImpl implements ProductService {
private Map<ProductType,ProductHandler> productHandlersMap = new EnumMap<>(ProductType.class);
@Autowired(required = false)
private List<ProductHandler> beanList;
@PostConstruct()
public void init() {
beanList.foreach(b->
productHandlersMap.put(b.getType(), b))
}
}