// 下階層用テンプレート
#topicpath
----
#contents
//ここにコンテンツを記述します。
Eclipseプラグイン開発をする上で、避けて通ることができないのが、org.eclipse.core.runtime.IAdaptable インタフェースです。このインタフェースは
***IAdaptableってなに [#e29fa6f9]

Eclipseプラグイン開発をする上で、避けて通ることができないのが、[[org.eclipse.core.runtime.IAdaptable:http://help.eclipse.org/help31/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/IAdaptable.html]] インタフェースです。このインタフェースは
 public Object getAdapter(Class adapter);
というメソッドだけが宣言されています。このメソッドはEclipseプラットフォーム側が、このインタフェースを実装したオブジェクトに対して「Class adapterに対応したモノ持ってる?もってたらかえして。。」というメソッドと言うことができます。
というメソッドだけが宣言されています。このメソッドはEclipseプラットフォーム側が、このインタフェースを実装したオブジェクトに対して「Class adapterに対応したモノ持ってる?もってたらちょうだい。。」てのを実現するためのメソッドとでもいえばよいでしょうか。

たとえば[[Eclipse/プラグイン開発のTIPS集/プロパティシートを使う]]などではビューやエディタに対して
   public Object getAdapter(Class adapter) {
    if(adapter.equals(IPropertySheetPage.class))
      return new PropertySheetPage();
    return super.getAdapter(adapter);
  }
などとやって、このビューはプロパティシートを使えるよー、なんてことを指定することができるという仕組みです。通常ならプロパティシートを使えるか、○○を使えるか、などさまざまなインタフェースを定義して実装するみたいな感じになりますが、これだとただひとつの汎用的なアダプタでそれを実現することができます。まさにアダプタです。

この緩やかさ(疎さ?)が、またわかりにくいなぁっておもったりもするんだけど。

***PlatformObject ってなに?IAdapterFactory てなに?? [#ia7bfa63]


さて、このIAdaptableインタフェースですが、すべてのClass adapterに対して返すモノを考えなくてはいけないのはしんどいので、デフォルトの実装として[[org.eclipse.core.runtime.PlatformObject:http://help.eclipse.org/help31/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/PlatformObject.html]] があるようです。でさらにそれに指示を与えるためのファクトリとして[[org.eclipse.core.runtime.IAdapterFactory:http://help.eclipse.org/help31/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/IAdapterFactory.html]] があります。つまりEclipseのIAdaptableの機構を理解するには
 org.eclipse.core.runtime.IAdaptable インタフェース
 org.eclipse.core.runtime.PlatformObject オブジェクト
 org.eclipse.core.runtime.Interface IAdapterFactory ファクトリ
 org.eclipse.core.runtime.IAdapterFactory ファクトリ
を理解する必要があるみたいですね。



***例1 [#zb5cbeac]
ためしに以下のIAdaptableなクラス
 class MyHashMap implements IAdaptable {
   private Map delegate = new HashMap();
   public int size() {return delegate.size();}
   public Collection values() {return delegate.values();}
 
   public Object getAdapter(Class clazz) {
     if (clazz == List.class) {
       List list = new ArrayList(delegate.size());
       list.addAll(delegate.values());
       return list;
     }
     return null;
   }
 }
を上の3つのクラスで実現してみたいと思います。ちなみにこのクラスはListくれーてEclipseがいうとListを返すHashMapみたいなもんです。つまり
 MyHashMap map = new MyHashMap();
 System.out.println(map.getAdapter(List.class).getClass().getName());
はjava.util.ArrayListとなります。まさにアダプタですね。


まず上のクラスをPlatformObjectを拡張するよう変更します。

 // class MyHashMap implements IAdaptable {
 class MyHashMap extends PlatformObject {
   private Map delegate = new HashMap();
   public int size() {return delegate.size();}
   public Collection values() {return delegate.values();}
 
   // public Object getAdapter(Class clazz) {
   // if (clazz == List.class) {
   // List list = new ArrayList(delegate.size());
   // list.addAll(delegate.values());
   // return list;
   // }
   // return null;
   // }
 }

つぎに、IAdapterFactoryを実装する、ListAdapterFactoryを作成します。
 class ListAdapterFactory implements IAdapterFactory {
   public Object getAdapter(Object adaptableObject, Class adapterType) {
     if (adapterType == List.class && adaptableObject instanceof MyHashMap) {
       MyHashMap map = (MyHashMap) adaptableObject;
       List list = new ArrayList(map.size());
       list.addAll(map.values());
       return list;
     }
     return null;
   }
 
   public Class[] getAdapterList() {
     return new Class[] { List.class };
   }
 }

以上で完成です。後は使うときに、ランタイムにこのファクトリをEclipseプラットフォームに登録します。具体的には以下の通りです。
 IAdapterFactory factory = new ListAdapterFactory();
 Platform.getAdapterManager().registerAdapters(factory, MyHashMap.class);
これで登録ができました。以上で、
 MyHashMap map = new MyHashMap();
 System.out.println(map.getAdapter(List.class).getClass().getName());
はやっぱりjava.util.ArrayListとなります。


......この例って、意味ある??使い方は何となくわかったけど、定義している場所が違うだけみたいな。。。。強いて言えば、動的にアダプタを切り替えたり、実装をこのファクトリに集約することができるとか??ちなみにプラットフォームから登録を解除するには
 Platform.getAdapterManager().unregisterAdapters(factory);
でOKです。





***例2 [#r6a0a2c1]
そもそもこの例をやりたかったのでした。Viewer系のModelと2つのプロバイダで、この機構が使われていたからです。具体的にはBaseWorkbenchContentProviderですね。

書きとちゅー。。。。。。


BaseWorkbenchContentProviderの実装を調べてみました。
 public Object[] getChildren(Object element);
をみてみると、elementオブジェクトがIAdaptableの場合、
 (IWorkbenchAdapter) ((IAdaptable) model).getAdapter(IWorkbenchAdapter.class);
とcastしてIWorkbenchAdapter#getChildren(Object element) を呼ぶ、という実装になってます。
つまりモデルとなるelementがどのようなIWorkbenchAdapterを持ってるか、で挙動が決まるって事ですね。









***関連リンク [#eda3e973]
-[[What is IAdaptable?:http://www.eclipsezone.com/articles/what-is-iadaptable/]]





----
この記事は
#vote(おもしろかった,そうでもない)

#comment
#topicpath


SIZE(10){現在のアクセス:&counter;}


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS