簡體   English   中英

將類A(和所有子類)映射到Java中的B類實例

[英]Mapping class A (and all subclasses) to instance of class B in Java

在Java中實現策略模式時,存在將輸入數據類型映射到特定算法的實例的常見問題。

例如,我們可以創建一個地圖:

map.put(Apple.class, new AppleHandler());
map.put(Orange.class, new OrangeHandler());

並在運行時解析給定數據類型的正確處理程序:

Apple a = new Apple();
map.get(a.getClass()).handle(a);

問題:在這樣的Map<Class<A>, B> Guava / Apache Commons等庫中是否有任何Map<Class<A>, B>實現,它們將處理多態類型?

例如,對於上面的映射可以這樣工作(假設GreenApple擴展Apple):

  map.get(Apple.class) == map.get(GreenApple.class);

我知道我可以編寫遍歷層次結構的實現,但我問的是OTS解決方案。

最簡單的解決方案是簡單地為具有多個類的處理程序添加多個映射條目:

map.put(Apple.class, new AppleHandler());
map.put(GreenApple.class, map.get(Apple.class));
map.put(Orange.class, new OrangeHandler());

這種方法的一些警告包括

  1. 如果你有很多課程,那么你的地圖可能會有點大。
  2. 如果外部源可以定義類型A新類並在運行時提供它們,那么您將需要某種方式來注冊它們(例如,通過在初始化時掃描類路徑,提供某種注冊API以供外部代碼使用,或者添加支持如果請求的密鑰不在地圖中,則遍歷層次結構)。

但是,如果您可以控制源,那么您可以在編譯時在類本身中進行“映射”:

interface A {
    B getHandler();
}

interface B {
}

class Apple implements A {
    public B getHandler() {
        return AppleHandler.INSTANCE;
    }
}

class GreenApple extends Apple {
}

class Orange implements A {
    public B getHandler() {
        return OrangeHandler.INSTANCE;
    }
}

現在,您只需調用其getHandler()方法即可為任何A類實例獲取處理程序。 由於getHandler()是合同的一部分,定義新類A外部源也必須實現它。

如果您無法更改類型A的來源或不想( 分離關注點等),那么您可以引入一個新類型包裝A來使用裝飾器模式定義映射。

我通過注釋解決了類似的問題

@Documented @Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Handler {
    Class<? extends AbstractHandler> value();
}

這樣我得到一個處理程序類而不是處理程序本身,但在我的情況下這很好。 您可以使用Class#newInstance或dependency injection來獲取處理程序實例。


另一種可能性是查找循環

for (Class<?>  cl = givenClass; cl != null; cl = cl.getSuperclass()) {
    Class<? extends AbstractHandler> result = map.get(cl);
    if (result != null) {
        return result;
    }
}
... handle "handler not found"

這適用於超類但不適用於接口。 它可以為它們擴展,但是你可能會遇到鑽石問題

我做了一次鑽石問題對我來說沒有問題,因為我的處理程序是嚴格優先考慮的。 我的最終優化解決方案是使用ConcurrentMap<Class<?>, <Class<AbstractHandler>>> ,每次遇到新類時我都會更新它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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