我想用 CDI 实现工厂模式。这里我们有一个商业案例示例:
客户端提供表示类型的字符串。根据这种类型,工厂返回接口的实现。
我知道有很多关于工厂模式和 CDI 的问题。我这里的区别是我根据运行时参数解析工厂返回的实现。
我正在考虑使用生产者方法,但后来我想不出如何将解析的实现注入到需要实现的 bean 中,因为这是一个运行时参数,在构建时不一定知道。
所以我想到了使用 Instance 类的非常直接的方法。
这是基本实现:
// the interface. Instances of this class are returned from the factory
public interface Product {
}
// one implementation may be returned by the factory
@ProductType("default")
public class DefaultProduct implements Product {
}
// another implementation may be returned by the factory
@ProductType("myProduct")
public class MyProduct implements Product {
}
// the qualifier annotation
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface ProductType {
String value();
}
// the Annotation implementation to select
// the correct implementation in the factory
public class ProductTypeLiteral extends AnnotationLiteral<ProductType>
implements ProductType {
private String type;
public ProductTypeLiteral(String type) {
this.type = type;
}
@Override
public String value() {
return type;
}
}
// the factory itself. It is annotated with @Singleton because the
// factory is only needed once
@Singleton
public class Factory {
@Inject
@Any
private Instance<Product> products;
public Product getProduct(String type) {
ProductTypeLiteral literal = new ProductTypeLiteral(type);
Instance<Product> typeProducts = products.select(literal);
return typeProducts.get();
}
}
在我看来,使用 Instance 是非常复杂的。
但这有一个主要缺点:
每次调用Instance.get()
方法时都会检索Product
. 这可能很好,但Instance
实例在内部保留了返回实例的引用。因此,只要Factory
生命和每次Instance.get()
被调用,内存中就会存在更多的实例,Product
并且永远不会被垃圾收集,因为引用仍然存在Instance
。
我想过不做Factory
单例,但这只是转移了问题,并没有解决它。当然,这违反了工厂模式。
我尝试的另一个解决方案是Instance
在注释的帮助下迭代而不是选择实现:
@Singleton
public class Factory {
@Inject
@Any
private Instance<Product> products;
public Product getProduct(String type) {
Product product = null;
for(Product eachProduct : products) {
ProductType productType = eachProduct.getClass().
getAnnotation(ProductType.class)
if(productType.value().equals(type) {
product = eachProduct;
break;
}
}
return product;
}
}
基本上这是有效的。现在每次根据给定的类型我检索相同的Product
. 这样内存就不会被消耗。但是当我有可能更优雅地解决正确的实现时,我不喜欢迭代集合。
你有什么想法可以解决这个问题吗?否则我可能不得不保留迭代解决方案。