簡體   English   中英

Java8 Supplier接口提供正確的類型化實例

[英]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和類加載器,但我似乎無法使模式非常正確。 任何指導贊賞!

因為你使用通配符泛型類型的Thingythingyclasses ,你基本上說: 該類型的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM