如何使用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和类加载器,但我似乎无法使模式完全正确。任何指导赞赏!
答案 0 :(得分:1)
因为您在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);
}
}
如果您希望它是类型安全的,那么您需要完全重新设计它,并且只有在编译器能够推断出类型时才使用通配符。
答案 1 :(得分:0)
有趣的挑战。我认为这就是你要找的东西:
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,但这是类型安全的。