我想用CDI實現工廠模式。這裏我們有商業案例: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.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
的相同實例。這樣內存不會被消耗。 但我不喜歡它迭代集合,當我有可能更加優雅地解決正確的實現。
你有什麼想法可以解決這個問題嗎?否則,我可能不得不保持迭代解決方案。
不@辛格爾頓連做什麼嗎?另外,似乎你並沒有考慮到你要返回的東西在CDI中已經有了自己的範圍/上下文,在你的工廠裏緩存它們是沒有意義的,從長遠來看,它會受到限制。 – covener
感謝您的評論!那麼我會說,在哪裏你注入'工廠'相同的實例使用。你說得對,我沒有緩存任何東西,但我的'Factory'中的'Instance'成員變量保存了get()方法返回的所有實例的引用。這是如何限制的? – Sancho
我沒想過將它設置爲「@ RequestScoped」,因爲就像在老式的工廠模式中一樣,工廠只存在一次。但是,也許我會試一試,仔細看看CDI示波器。無論如何感謝@rdcrng! – Sancho