Java 是強型別語言,每個實例皆有宣告型別(靜態型別)與執行時型別(動態型別)。呼叫方法時,該方法必須存在於宣告型別中。例如 List list = new ArrayList(); 可呼叫 list.add(),但無法直接呼叫 ArrayList 專有的 ensureCapacity(),除非進行強制轉型或 instanceof 檢查。
類別無法總是實作所需介面:或許該介面僅適用少數情境、來自無關聯的庫、或後期才新增。Eclipse 引入 IAdaptable 解決此問題,允許動態型別轉換:
IAdaptable adaptable = new HashMap();
List list = (List) adaptable.getAdapter(java.util.List.class);
核心在於 getAdapter(Class) 可回傳目標介面的實作,即使原物件未實作該介面。這本質上是一種「代理」機制:回傳包裝後的物件而非直接轉型,若不支援則回傳 null 而非拋出例外。
public class HashMap implements IAdaptable {
public Object getAdapter(Class clazz) {
if (clazz == java.util.List.class) {
List list = new ArrayList(this.size());
list.addAll(this.values());
return list;
}
return null;
}
}
Eclipse 提供抽象類別 PlatformObject,已實作 IAdaptable 並將 getAdapter() 委派給 IAdapterManager(可透過 Platform.getAdapterManager() 取得)。管理器內部維護一個巨大的對應表,將類別與適配器關聯,支援動態註冊新適配器而無需重新編譯。
假設需將裝有字串的 List 轉為 XML 節點:
<List>
<Entry>First String</Entry>
<Entry>Second String</Entry>
<Entry>Third String</Entry>
</List>
三步驟完成:
List 轉為 XOM 的 Node。Platform.getAdapterManager().registerAdapters(new NodeListFactory(), List.class);(或透過 org.eclipse.core.runtime.adapters 擴充點隱式註冊)。Node node = (Node) list.getAdapter(Node.class);java.util.List 非類別無法繼承 PlatformObject,可採用組合模式實作 IAdaptable:
public class AdaptableList implements IAdaptable, List {
public Object getAdapter(Class adapter) {
return Platform.getAdapterManager().getAdapter(this, adapter);
}
private List delegate = new ArrayList();
// 委派所有 List 方法給 delegate...
}
IAdaptable 搭配 AdapterManager 實現「執行時為既有類別動態新增功能」,達到非 UI 元件與 UI 元件完全解耦。此機制廣泛應用於 Eclipse 專案(如屬性視圖與資料模型分離),是打造可擴充架構的關鍵。