[英]Java8 Supplier interface to provide the proper typed instance
如何使用Java8 Supplier接口重寫此工廠方法以提供正確的類型化實例?
我有一個擴展Map的簡單界面:
public interface Thingy<K, V> extends Map<K, V> {}
然后我有一個ThingyFactory類,其中包含Thingy所有實現類名的列表:
public final class ThingyFactory {
Map<String, Class<Thingy<?, ?>>> thingyclasses = new ConcurrentHashMap<>();
.....
@SuppressWarnings("unchecked")
public <K, V> Thingy<K, V> getInstance(String classname) throws ThingyException {
Thingy<K, V> thingy;
try {
thingy = (Thingy<K, V>) thingyclasses.get(classname).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new ThingyException("Something bad happened: ", e.toString());
}
return thingy;
}
}
我很確定我能夠優雅地完成這項任務,並且沒有使用供應商界面的SuppressWarnings和類加載器,但我似乎無法使模式非常正確。 任何指導贊賞!
因為你使用通配符泛型類型的Thingy
內thingyclasses
,你基本上說: 該類型的Thingy
可以是任何東西 ; 但是,這會禁止編譯器推斷有關類型的任何內容,因此需要顯式轉換。 您可以使用“ Supplier
略微改進它,但您仍然會收到有關未經檢查的強制轉換的警告:
class ThingyFactory {
private Map<String, Supplier<Thingy<?, ?>>> providers = new ConcurrentHashMap<>();
@SuppressWarnings("unchecked")
public <K, V> Supplier<Thingy<K, V>> getInstance(String classname) {
return () -> (Thingy<K, V>) providers.get(classname);
}
}
如果您希望它是類型安全的,那么您需要完全重新設計它,並且只有在編譯器能夠推斷出類型時才使用通配符。
有趣的挑戰。 我想這就是你要找的東西:
public class Main {
public static void main(String[] args) {
ThingyFactory<String, String> factory = new ThingyFactory<>();
Thingy<String, String> instance = factory.getInstance("ThingyImpl");
System.out.println(instance.clazzName());
Thingy<String, String> otherInstance = factory.getInstance(ThingyImpl.class);
System.out.println(instance.clazzName());
}
}
interface Thingy<K, V> extends Map<K, V> {
//added this method for testing purpuses
String clazzName();
}
//extending HashMap so I don't have to implement Map's methods
class ThingyImpl<K, V> extends HashMap<K, V> implements Thingy<K, V> {
public String clazzName() {
return "ThingyImpl";
}
}
final class ThingyFactory<K, V> {
private Map<String, Supplier<Thingy<K, V>>> providers = new ConcurrentHashMap<>();
public ThingyFactory() {
providers.put("ThingyImpl", () -> new ThingyImpl());
}
public Thingy<K, V> getInstance(String classname) {
return providers.get(classname).get();
}
// alternative with Class.
// You could change providers to a Map<Class<? extends Thingy>, Supplier<Thingy<K, V>>>
public Thingy<K, V> getInstance(Class<? extends Thingy> clazz) {
return providers.get(clazz.getName()).get();
}
}
當然,對於每個特定的K,V類型對,您都需要一個ThingyFactory,但這是類型安全的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.