processメソッドは、引数にメンバー処理ビジターを与えることで、汎用的に記述されています。この拡張処理メソッドが、第1引数にactionSets拡張ポイントの識別子、すなわちorg.eclipse.ui.actionSetsをともなって呼び出されると仮定します。actionSets拡張ポイントに対する拡張機能の1つが、リスト2.4のヘルプ拡張機能であり、1つのactionSetメンバーをもっています。外側のループでヘルプ拡張機能に到達すると、actionSetメンバーが内側のループに与えられ、メンバー処理ビジターによって処理されます。workbenchのUIプラグインで、このプラグインがアクティブになるときに見られます。UIプラグインは、IConfigurationElementと関連するインターフェイス・メソッドを使って、actionSetメンバーの属性とサブ要素を取り出します。これらを使って指定されたメニューとボタン要素をworkbenchのユーザー・インターフェイスに組み込み、必要になるとコールバック・オブジェクトをインスタンス化します。)、ホスト・プラグインは各メンバーを処理するのに必要なことは何でも自由に行なうことができます。メンバーはXML構成要素として与えられます。拡張ポイント全体、すなわちIExtensionPointインターフェイスに対して、同一のシグネチャーをもつメソッドも存在します。このメソッドは、拡張ポイントに対する全拡張機能の全メンバーの構成要素を返します。)は、拡張ポイントの全拡張機能の全メンバーを処理する単一のループに還元されます。拡張ポイントを処理するのに、このより単純な慣用句で十分なことがよくあります。)に、具体的な拡張処理ビジターを与えることによって、拡張処理の動作を体験できます。特定の拡張ポイントに対するすべての拡張機能メンバーについて識別情報を出力するには、以下に示すビジター・インターフェイスIProcessMemberの実装を使用できます。拡張ポイント・メンバーの識別データの印刷actionSetメンバーには名前がlabelのラベル付け用の属性があり、workbenchの現在のインスタンス内に存在するすべてのactionSetsについて、その識別情報を印刷するには、次の呼び出しを使用します。"label")この呼び出しは、以下のような出力行を生成します。Navigation...この拡張処理のデモは、この記事のcompanionプラグインにあります。デモを試すには、記事の最後にあるプラグインのインストール方法を参照してください。拡張処理の最も重要な機能は、拡張機能コールバック・オブジェクトのインスタンス化です。manner)によって実行されます。本節では、この重要なパフォーマンスの最適化を無視し、かわりにコールバックのインスタンス化における主要な機能の側面に集中します。Eclipseはコールバック・オブジェクトをインスタンス化し、初期化するための標準的な方法を定義しています。述べたように、コールバック・オブジェクトは、通常、拡張機能の独自の子供レベルまたは子孫レベルのXML要素内に記述され、完全修飾クラス名がこの要素の属性値として与えられます。コールバック・オブジェクトの初期状態は、普通、対応する要素とその子孫要素によって完全にパラメーター化されます。これらの条件を満たすと、Eclipseが備える標準のコールバック・オブジェクトのインスタンス化、および初期化機能を使って、コールバック・オブジェクトをインスタンス化し、初期化することができます。拡張処理コードが、独自のコールバック・オブジェクト(たとえば、actionSets拡張機能内でactionの役割を担うオブジェクト)に対応する要素への拡張機能メンバーの構文解析された表現を取得していると仮定します。elementに格納され、コールバック・オブジェクトの完全修飾クラス名を指定する要素の属性名がclassであるとします。classPropertyName)が、コールバック・オブジェクトをインスタンス化するのに使用されます。element.createExecutableExtension("class")ICallbackは、対応するコールバックの役割に応じて与えられるインターフェイスです。createExecutableExtensionメソッドは、2つのことを行ないます。引数なしのパブリックなコンストラクター(必要です)を使って、必要なクラスのメンバーをインスタンス化する。必要なクラスの完全修飾名は、メソッドのclassPropertyName引数で与えられる名前をもつ属性の値として、構成要素内で検索されます。標準の方法でこのインスタンスを初期化できるときは、初期化する。IExecutableExtensionを実装します。CoreException;}インスタンス化されたコールバック・オブジェクトがIExecutableExtensionのインスタンスであれば、createExecutableExtensionメソッドは、自動的にこの拡張機能オブジェクトのsetInitializationDataを呼び出し、コールバック・オブジェクトの構成要素をパラメーターとして引き渡します。(引数にはクラスの属性名とデータ・パラメーターもありますが、これらの詳細はこの記事の範囲を越えています。さしあたっては、無視してもかまいません(Eclipseのドキュメントで詳しく説明されています))もちろん、この初期化メソッドで実際に何を行なうかは、コールバック・オブジェクトの設計者次第です。このメソッドにパラメーターとして与えられるコールバック・オブジェクトの構成要素が、初期化プロセスを起動し、初期化メソッドによってコールバック・オブジェクトの状態に反映されます。第4節で、この仕組みを使ってコールバック・オブジェクトをインスタンス化し、初期化する完全な実例を示します。以前にも述べたし、次節でも説明するように、この全体の仕組みは一般に遅延方式で、たとえば独自の作業を行なうためにコールバック・オブジェクトが実際に必要になったときにだけ使用されます。同様に、コールバック・オブジェクトの初期化メソッドも、時間のかかる作業を、オブジェクト上の後続のメソッド呼び出しがこの作業を必要とするか、この作業からメリットを得られるまで、可能な限り遅らせる必要があります。コールバック・オブジェクトがリソース・セットへのアクセスを管理する場合、コールバック・オブジェクトへの後続のメソッド呼び出しが管理されたリソースを実際に必要とするときにはじめて、そのリソースをオープンすることは、しばしば可能であり、より望ましいことです。遅延拡張処理ホスト・プラグインがアクティブになると、拡張機能の熱心な(eager)処理は、すべてのエクステンダー・プラグインと、再帰的にプラグイン階層を下って、より正確にはプラグイン拡張ネットワークをたどって、関連するエクステンダー・プラグインをアクティブにします。特定のプラグインから到達可能なすべてのプラグインのアクティブ化は、それらのクラスのロードをともないます。このようなプラグインの全拡張ポイントの処理は、拡張ポイントに対する全拡張機能のカスタム・コールバック・クラスのロードを意味します。その結果、熱心な拡張処理方式では、プラグインをアクティブにするのにかなりの時間がかかり、システムの起動も遅くなります。そのため、プラグイン開発者は、エクステンダー独自のコールバック・オブジェクトの作成を、このオブジェクトがアクションを実行するために実際に必要になるまで遅らせることにしました。proxy)の使用があります(参考文献[1]にあるプロキシー・パターンの仮想的用法を参照)。このようなプロキシーは、実際のコールバック・オブジェクトの役割を代行し、実際のコールバック・オブジェクトはアクションによって必要になったときにだけインスタンス化されます。場合、プロキシー・クラス中にコールバック・オブジェクトを必要とする汎用関数を用意することができます。このような関数は、特定のカスタム拡張機能クラスを参照しないでホスト・プラグインに組み込むことができる上、特定のエクステンダー・プラグインをアクティブにする必要もありません。仮想プロキシーを使ってホスト・プラグインの拡張機能を初期化すると、限られた数の拡張機能クラスだけが、すなわち各拡張ポイントの役割に対して1つのクラスだけが、ホスト・プラグインのアクティブ時にロードされます。例として、内部パッケージorg.eclipse.ui.internalには、UIアクションに対するPluginActionと呼ばれる抽象仮想プロキシー・クラスと多くの具体的なサブクラスが含まれています。actionSets拡張ポイントへの最初の拡張処理では、各UIアクションに対してこのようなプロキシー・クラスだけがインスタンス化されます。アクション・プロキシーに対する一般的なコンストラクターは抽象クラスPluginActionで定義され、次に示すシグネチャーをもっています。style)actionElementパラメーターは、アクションを表わす拡張機能XML要素の構文解析された表現への参照を提供し、runAttributeパラメーターは、アクションを実行するためにインスタンス化されるカスタム・アクション・クラスの名前を表わすXML属性を特定します。PluginActionプロキシー・クラスは、後でこれらのプロパティを実際のアクション・オブジェクトをインスタンス化し、初期化するのに使用するために、単に記憶しておくだけです。プロキシー・クラスは、IActionと呼ばれるworkbenchのアクション・インターフェイスを実装することによって、アクション呼び出しを処理します。このインターフェイスのrunメソッドがはじめて呼び出されると、プロキシーはrunAttributeで与えられた名前をもつカスタム・アクションの実装クラスをインスタンス化し、runメソッド呼び出しがこのカスタム・アクションのインスタンスにディスパッチされます。delegate)として知られています。正規のプロキシー・パターンでは、プロキシー・クラスとデリゲートを実装するクラスの両方が、同じ機能インターフェイスを実装します。コールバック・オブジェクトの仮想プロキシーの実装では、プロキシー・パターンの厳密な解釈にならう必要はありません。実際、アダプター(adapter)パターンにならった実装は、コールバックの遅延インスタンス化の目的に対しては、より柔軟なメカニズムを提供します。adapter)として記述されています。このハンドラーは、高レベルのIActionインターフェイスを実装し、カスタム・アクション・コールバックの実装で要求されるより低レベルのIActionDelegateインターフェイスに適合させます。IActionとIActionDelegateの2つのインターフェイスは無関係であり、ハンドラー・クラスPluginActionは、独自のカスタム・アクション・ハンドラーを参照することなく、いくつかの基本サービスを提供し、要求されたアクションを実際に実行するために、workbenchのIActionインターフェイスのrunメソッドをアクション・コールバックのIActionDelegateインターフェイスのrunメソッドに適合させます。(第2.3.1.3.1節で述べたカスタムworkbenchメニューとボタン・ハンドラーに要求されるIWorkbenchWindowActionDelegateインターフェイスは、アクション・コールバック・インターフェイスIActionDelegateから派生しています。)Eclipse開発者が、コールバックの遅延インスタンス化を実現するのに、厳密なプロキシー手法を使う必要はありませんが、Eclipseではプロキシーという用語は、カスタム・コールバック・オブジェクトのインスタンス化を遅らせる目的で、このオブジェクトの前段(front)として使用される内部オブジェクトを指すときに、普通に使用されます。拡張可能な演算関数サービスこれまで、すでに存在する拡張ポイントだけを扱ってきましたが、拡張処理の仕組みを使って自己の拡張ポイントを作成する準備が整いました。実例として取り上げる拡張ポイントは、これまで扱ってきたactionSets拡張ポイントに大枠の構造が似ています。カスタム・サービス・セットによってホスト・プラグインの機能を拡大するためのスロットを提供する。そのため、各拡張機能はホスト・プラグインに複数のサービスを自由に追加できる。各拡張機能は提供するサービスを実現する具体的なコールバック・オブジェクトを用意する必要がある。ホストは各拡張機能(実際には、各拡張機能のメンバー)に対して、要素をユーザー・インターフェイスに追加する責務を負う。これによって、ユーザーは拡張機能が提供するサービスと相互作用できる。実例では、Eclipseが備えている標準のコールバック初期化機能を使って、コールバック・オブジェクトを独自に初期化する機能も提供します。目的は、できるだけ単純な拡張ポイントを使って、拡張機能のこれらの顕著な特徴を示すことです。主な関心は、アーキテクチャー上の問題点、パターンの用法、および拡張処理を示すことにあります。ここでは、ユーザー・インターフェイス設計の問題は扱いません。実際、実例では、ユーザー・インターフェイス機能と拡張処理機能との間で必要になる相互作用のタイプを示すのに足りる程度の、ごく単純なユーザー・インターフェイスを使用するだけです。plug-in)と呼ばれます。単一の拡張ポイントがUIプラグインで定義され、非常に単純なタイプのサービスでプラグイン拡張をサポートします。サービスは、1つの引数をとる整数型演算関数へのアクセスを提供します。関数のシグネチャーは、以下に示すコールバック・インターフェイスで定義されます。ArithmeticException;}実例では、各拡張機能メンバーは、IFunctionインターフェイスを実装するコールバック・オブジェクトを通して、このような関数の実装を提供します。標準の拡張処理を使ってコールバック・オブジェクトを初期化する方法を示すために、拡張機能の宣言内でXML属性として与えられる構成パラメーター(計算で使用される定数)を介して関数を構成するようにします。パラメーターの加算、乗算などのさまざまなコールバック・クラスで実装される異なる計算のクラスがあります。一般に、各タイプの計算は別々にパラメーター化されます。単純にするために、計算機能は高々1つの整数パラメーターでパラメーター化されるものとします。引数の値を2倍する関数は、定数因子2で乗算されるとみなします。この場合、値2は、対応するコールバック・オブジェクトの拡張機能宣言内で、XML構成パラメーターとして与えられます。UIプラグインは、サービス関数の引数を入力する入力フィールド、関数の値を表示する結果フィールド、および計算処理で使用される定数パラメーター(もし、あれば)を表示する定数(constant)フィールドを提供します。各関数には、関数を起動するための独自のボタンと、関数についての情報を表示するための独自のラベルも必要です。そのため、各拡張機能メンバーに対して、UIプラグインはユーザー・インターフェイスに対応するボタンとラベルを追加します。ボタンが選択されると、UIプラグインは関連するサービス関数をコールバックします。図2は、エクステンダー・プラグインの典型的な構成に対するUIプラグインのユーザー・インターフェイスを示しています。サービスUIプラグインの関数起動画面。ホスト・プラグインの拡張機能は、この画面を通してアクセスされる演算関数を宣言する。UIプラグイン・クラスはcom.bolour.sample.eclipse.service.uiで、拡張ポイントはfunctionsと呼ばれます。拡張ポイントfunctions拡張ポイントは、UIプラグインのマニフェスト・ファイル内で以下のように宣言されます。schema="schema/functions.exsd"/>この拡張ポイントに対するリファレンス・ページが用意されています(拡張機能のスキーマ・ファイルのソースfunctions.exsdは、companionプラグインzipファイルにあります)。リファレンス・ページに記載されているように、functions拡張機能は、以下の属性をもつfunctionメンバーのシーケンスです。メンバー関数のカスタム・コールバック・クラス。ユーザー・インターフェイス上で関数をラベル付けするのに使用される。定数によってメンバー関数をパラメーター化するのに使用されるオプションの属性。次節で、これらの属性を使った拡張機能の完全な実例を示します。対する拡張機能メンバー宣言の例を示します。class="com.bolour.sample.eclipse.service.multiplication.Multiplication"/>この場合、Multiplicationクラスは、標準のEclipseコールバック初期化インターフェイスIExecutableExtensionを実装し、与えられた定数因子でそのインスタンスを初期化します。第4.3.2節で、詳しく説明します。計算処理の設計者は、定数によるパラメーター化を行なわないことがあります。(第4.3.1節を参照)は、このようなパラメーター化を行なわない計算処理の実例です。この場合、対応するコールバック・オブジェクトに対して独自の初期化は必要でないため、関連するコールバック・クラスはIExecutableExtensionを実装しません。図3は、関数UIプラグインとその拡張機能との間の関係を示しています。セットが、プラグインのfunctions拡張ポイントの拡張によってUIプラグインに追加される。これで、functions拡張ポイントに対してサンプルの拡張機能を作成するのに必要なすべての情報が揃いました。UIプラグインの実装の詳細に進む前に、この拡張ポイントに対する拡張機能のサンプルを示します。第4.3節では、このような拡張機能について、2つのサンプルを示します。第4.4節で、UIプラグインにおける拡張処理の詳細を示し、再びこのプラグインの実装に戻ります。シンプルな拡張機能エコー・サービスは、入力を出力にそのまま返す関数を提供します。そのサービス・クラスは、以下のように定義されています。エコー・コールバック関数クラスfunctions拡張ポイントを拡張することで、ユーザーはエコー・プラグインを利用できるようになります。エコー拡張機能の仕様を、以下に示します。エコー拡張機能の仕様この仕様では、サービス・コールバック・クラスを宣言し、サービス演算の名前にECHOと指定しています。この単純なケースでは、Echoオブジェクトは独自の状態をもたないため、初期化の必要はありません。そのため、オプションのconstant属性は使用されず、Echoコールバック・クラスは、IExecutableExtensionインターフェイスを実装しません。入力引数を定数値で乗算するサービス関数を提供するとします。必要な乗算因子をインストール時に構成できると、このようなサービスはより有用になります。function要素のconstant属性は、この目的で使用されます。サンプルの乗算拡張機能を、以下に示します。乗算拡張機能の仕様この拡張機能が処理されると、constant属性は乗算因子として解釈されます。乗算コールバック・クラスを、以下に示します。)は、標準の初期化インターフェイスIExecutableExtensionの実装を提供します。次節では、functions拡張ポイントに対する拡張処理が、標準のコールバック・インスタンス化メソッドcreateExecutableExtensionを使用しています。MultiplicationクラスはIExecutableExtensionインターフェイスを実装しているため、createExecutableExtensionメソッドは、パラメーターにそのインスタンスの構文解析されたXML要素を与えて、コールバック・インスタンスのsetInitializationDataメソッドを自動的に呼び出します。「functions」拡張ポイントの処理いくつかのサンプル・テスト・ケースを使ってfunctions拡張ポイントを試し、この拡張ポイントの実装とUIプラグインの定義についてより詳しく調べる準備が整いました。この例では、拡張処理クラスはProcessServiceMembersと呼ばれます。このクラスは、Eclipseの拡張処理で用いられる標準的な慣用句を取り入れ、functions拡張ポイント用に特殊化しています。このクラスでは、functions拡張ポイントに対して標準的な遅延手法を使って拡張処理を実装しています。FunctionsGridと呼ばれる独立したUIクラスは、UIプラグインに対するすべてのUI処理をカプセル化します。一般に遅延拡張処理では、アプリケーション操作の2つの異なるフェーズでの処理が必要になります。ホスト・プラグイン起動フェーズでは、全拡張機能メンバーの構成を取得し、汎用的なコールバック・プロキシーを作成して、ホスト・プラグインのユーザー・インターフェイスを構築するために、functions拡張ポイントの全拡張機能メンバーをはじめて走査します。アプリケーション相互作用フェーズでは、各構成関数の計算処理を実行するのに必要な独自のコールバック・オブジェクトが遅延手法によって作成され、呼び出しはプロキシー・オブジェクトで受信されます。このフェーズの間、関数に対するUIボタンの選択は、拡張処理クラスが提供するプロキシー・コールバック・オブジェクトを通して、その関数にコールバックされます。呼び出しは、プロキシーによって実際のコールバック・オブジェクトに委譲されます。各プロキシーが最初に呼び出されたときに、実際のコールバック・オブジェクトが標準の拡張処理を介してインスタンス化され、初期化されます。第4.4.1節では、拡張処理クラスを概説します。第4.4.2節では、拡張処理と相互作用するUIクラスの部分を概説します。UIの詳細を実装する大量のユーザ・インターフェイス・コードは、拡張処理とは直接関係ないため、この記事では扱いません。拡張処理クラス拡張処理関数の最初のバージョンを、以下に示します。コードは読みやすく編集されています。)は、第3.1.1節で紹介した拡張ポイントの全拡張機能のメンバーを取得するための簡略化イディオムにしたがっています。)、このプロキシーと関連するUIウィジェットをUIに追加します。addFunctionメソッドの本体を示します)実例にでてくる不正定数などの特定の構成エラーは、一般的な方法で、すなわち(インスタンス化を遅延しているため)独自のコールバック・オブジェクトに頼ることなく検出されます。このようなエラーは、初期の拡張処理の間に処理されるものです。そのため、ホスト・プラグインでは、不正なコールバック・オブジェクトや関連するウィジェットになるべく直面しないようになっています。アプリケーション相互作用フェーズの間に、関数呼び出しがコールバック・プロキシーで受信されると、この呼び出しは関数のカスタム実装に委ねられ、実装は呼び出しがプロキシーで最初に受信されたときに遅延手法を使ってインスタンス化されます。以下のコード断片に、詳細が示されています。サービス関数に対する拡張機能メンバー処理このコードは仮想プロキシー・パターンをそのまま手を加えずに使用しているので、これ以上注釈しません。エラー処理については次節で解説します。前節で述べたように、特定の構成エラーは、初期の拡張処理の間に一般的な方法で検出することができ、その時点で処理されました。残念ながら、すべての構成エラーがこのように処理できるわけではありません。遅延手法を使ってコールバック・オブジェクトの初期化を遅らせることは、コールバック・オブジェクトのインスタンス化と初期化に関係するエラーの検出も遅れるということになるからです。time)の構成エラーと呼ぶことにします。相互作用時の構成エラーは、2つのカテゴリーに分類されます。インターフェイスの不一致は、コールバック・クラスが必要なインターフェイスを実装していないときや、作成または初期化エラー、たとえば、存在しないクラスや不正な構成パラメーター(たとえば、除算関数に対する0の分母)などで見られます。コールバック・オブジェクトの初期化におけるエラーも含め、createExecutableExtensionの実行中に検出されたエラーは、CoreException例外を介して呼び出し側に通知されます。実例では、相互作用時の構成エラーが発生すると、ArithmeticException例外が投入されます。UIの例外処理では、関数起動画面の結果フィールドに単にエラーを表示しているだけです。実例のような単純なアプリケーションでは、このように誤って構成された関数に関連するUI要素を無効にはしていません。そのため、構成エラーが検出されても、ユーザーは同じ失敗を繰り返すことになります。洗練されたアプリケーションでは、拡張機能の誤って構成されたメンバーに関連するユーザー・インターフェイス要素を動的に無効にしたり、削除することがあります。companionプラグインzipファイルには、構成エラーを例示するサンプル・プラグインerrortestが含まれています。デフォルトでは、このようなエラーを含むfunctions拡張機能は、コメントアウトされています。このアプリケーションで、構成エラーの効果を試すには、errortestプラグインのマニフェスト・ファイル内にあるfunctions.error拡張機能のコメントを取り除いてから、Eclipseを再起動してください。遅延拡張処理による構成エラーの遅い検出は、構成エラーを適切に処理することをより困難にします。一般にアプリケーション起動時のパフォーマンス、適切なエラー処理、および特定の役割を担うコールバック・オブジェクトのカスタマイズ性の間には、矛盾する関係が存在します。ユーザー・インターフェイス・クラス本節では、拡張処理クラスと相互作用する範囲内で、UIプラグインのユーザ—・インターフェイス・クラスを概説します。functions拡張ポイントの拡張機能に含まれる各関数の仕様に対して、初期の拡張処理では、関数起動ボタンと対応するラベルがUIプラグインのユーザー・インターフェイスに追加されます。この目的で使用されるUIコードの簡略バージョンを、次に示します。このメソッドは、4つの引数をとります。ボタンが選択されたときに呼び出されるコールバック・オブジェクトを指定します。関数ボタンの表示名を指定します。関連ラベルのテキストを指定します。計算処理で使用される定数パラメーター(もしあれば)を指定します。定数は、表示の目的のためだけにUIに渡されます。対応するボタンが選択されると、計算処理の結果とともに表示されます。addFunctionメソッドの各起動は、同じパラメーターをもつGridRowのコンストラクターに委譲されます。GridRowクラスは、ユーザー・インターフェイス上の関数表現をカプセル化します。)とボタンを関連付けます。計算処理で使用された定数パラメーター(もしあれば)も表示します。ついての説明を終了します。この記事のcompanionサンプルには、関数起動UIプラグインとサンプルのエクステンダー・プラグインが含まれています。companionプラグインを編成するには、記事の最後にある指示を参照してください。pattern)とも言うべき単純な実例を示しました。extension)の各メンバーは、固有のユーザー・インターフェイス・ウィジェット・セットと、これらのウィジェット上で固有の拡張機能オブジェクトにコールバックを引き起こすイベントを定義しています。拡張機能の実装に他のパターンを適用することもできます。本節では、参考文献[1]のオブザーバー・デザイン・パターンに類似した、このようなパターンの1つを簡単に説明します。このパターンの適用を通して、Eclipse拡張モデルと非常に単純なオブザーバー・パターンとを比較します。pattern)と呼ばれるものです。リスナー拡張パターンでは、複数の拡張機能メンバーが、ホスト・プラグインで発生する同じイベントを受信することがあります。イベントが発生すると、ホスト・プラグインはすべての拡張機能メンバー、正確には拡張機能メンバーに関連するリスナー・コールバックに通知します。workbench内の複数のオブザーバーが、JUnitテストの開始や終了などのテスト・イベント通知を取得できます。BeckとGammaの草稿[2]で、この用法を取り上げています。この草稿で、はじめてリスナー拡張パターンを知りました。リスナー拡張パターンでは、ホスト・プラグインはオブザーベーションのサブジェクト(subject)として動作し、エクステンダー・プラグインはオブザーバー(observer)またはリスナー(listener)として動作します。そのため、ホスト・プラグインは、listenersと呼ばれる拡張ポイントとIListenerと呼ばれる対応するインターフェイスを提供します。各エクステンダー・プラグインは、IListenerインターフェイスを実装する独自のリスナー、またはリスナーのシーケンスを供給することによって、listeners拡張ポイントを拡張します。リスナーは、プラグイン拡張メカニズムを通して宣言的に指定され、拡張処理によってイベント通知に自動的に登録されます。最初の通知が必要になると、サブジェクト・プラグインはlistenersメンバーを処理し、各メンバーに対して、独自のリスナー・コールバック・オブジェクトをインスタンス化して、イベント通知にそのリスナーを登録します。companionサンプル・プラグインには、リスナー拡張パターンの実例が含まれています。図4に、その構造を示します。リスナー拡張パターンの拡張構造。各リスナー拡張機能のメンバーは、サブジェクトのイベントに対して通知コールバックを提供する。この例では、サブジェクトが更新されると、listeners拡張ポイントに対する全拡張機能の全メンバーに通知がブロードキャストされます。listeners拡張ポイント・リファレンス・ページを参照してください。ボックスの外側に記しているように、この例には、listeners拡張ポイントを拡張する2つのプラグインが含まれています。それぞれ、firstlistener、secondlistenerと呼ばれ、それぞれが2つのlistenerメンバー、ListenerXとListenerYを含んだ拡張機能をもっています。したがって、1つ目のリスナー・プラグインの拡張機能仕様は、以下のようになります。リスナー拡張機能の仕様。ホスト・プラグインが定義しているメニュー項目を選択すると、サブジェクトの状態が更新されます。サブジェクトの状態変化によって、リスナー通知がシステムに登録されている各リスナーにブロードキャストされます。この例におけるリスナー・コールバックは、取るに足らないささいなものであり、以下のリスナー・クラスで示すように、単に標準出力に情報メッセージを出力するだけです。リスナー・コールバックの実装。コンソール・ボックスからこの例を実行すると、以下のコンソール・メッセージが表示されます。オブザーバー・パターン今まで見てきたように、リスナー拡張パターンは、インストール時にリスナーが静的に登録されることを除いてオブザーバー・パターンに似ています。オブザーバー登録における動的な性質を無視すれば、オブザーバー・パターンは、Eclipse拡張モデルの特殊化と考えられます。実際、動的登録を差し引いても、Eclipse拡張モデルは多くのレベルでオブザーバー・パターンを強化しています。単一の拡張機能が、複数のコールバック・オブジェクトを提供できます。単一のオブザーバーは、1つのコールバック・オブジェクトしか提供できません。オブザーバーの一様な扱い。拡張機能パラメーターと拡張ポイント契約の仕様にしたがって、特定の拡張ポイントに対する異なる拡張機能は別々に扱われます。これに反して、オブザーバー・パターンは特定のサブジェクトのすべてのオブザーバーを一様に扱い、1つのオブザーブ・イベントをすべてのオブザーバーに通知します。サブジェクトにおける固定の通知セマンティック。ホストのセマンティックは、拡張機能のインスタンスと結びついて、任意にパラメーター化されます。拡張機能の構成に基づいて、ホストは拡張機能の契約下で、たとえばユーザー・インターフェイス要素の表示などのさまざまなカスタマイズ可能な責務を果たします。オブザーバー・デザイン・パターンには、このようなパラメーター化やカスタマイズ性はありません。server)によるマイクロカーネル(microkernel)拡張モデル(実例は、参考文献[4]のマイクロカーネル・パターンを参照)との間には、よりいっそうの類似点が見られます。両方のモデルとも、プロバイダーが提供するサービスの追加によって、基本サービス・セットを拡張できます。Eclipse拡張モデルは、2つの方法でマイクロカーネル・アーキテクチャーの内部拡張モデルを一般化します。第1に、Eclipseプラグインは、関連する拡張機能セットをパッケージ化するメカニズムを提供しています。第2に、Eclipseでは、すべてのプラグインが拡張ポイントを用意して他のプラグインによってそれ自体を拡張できます。これに反して、マイクロカーネル・アーキテクチャーでは、マイクロカーネルのコア(たとえばOSカーネル)だけがシステムで唯一の拡張可能なコンポーネントとして特別な立場にあります。まとめと結論Eclipseプラグイン拡張モデルは、疎結合された(loosely-coupled)コンポーネントに基づいて拡張可能なシステムを設計するためのパワフルで汎用的なパラダイムを提供します。workbenchです。基本となる拡張モデルは、workbenchに特有の具体化とはまったく別の抽象的なアーキテクチャー・パターンです。この抽象モデルの原理をなす機能は、インストール時に組み込み可能なコンポーネント。プラグインは、インストール時にシステムに組み込まれるコンポーネントで、プラグイン・クラスのインスタンスとして稼動中のシステムに実装されます。各プラグインの特性はマニフェスト・ファイル内で宣言的に指定され、プラグインをインスタンス化し、他のプラグインに関連付けるために実行時に解釈されます。プラグイン自体を拡張するという独特の方法は、拡張ポイントを使って実現されます。拡張ポイントは、ホストの役割を担うプラグインによって定義され、エクステンダーの役割を担う複数のプラグインによって拡張されます。各拡張ポイントに付随する契約があり、ホスト・プラグインとエクステンダー・プラグインの両方に責務を課します。パラメーター化されるコールバック・バンドルとしての拡張機能。拡張ポイント契約は一般に複数のコールバック・インターフェイスを提供し、エクステンダーは、これらのインターフェイスに対してカスタム実装(コールバック・オブジェクト)を提供する必要があります。ホストは、契約で指定された特定の条件下で、独自の拡張機能構成パラメーターに基づいてこれらのコールバック・オブジェクトをコールバックする責務を負っています。拡張ポイント契約下でのホストの責務には、処理要素の追加によってホストのインターフェイスを拡張するなどの、ホストの動作への追加要件が含まれます。エクステンダーの責務。エクステンダーは、マニフェスト・ファイル内で拡張機能の特性を宣言的に記述します。拡張ポイント契約はこの記述に対してXMLスキーマを提供し、エクステンダーのマニフェスト・ファイル内の拡張機能仕様は、このスキーマに適合する必要があります。スキーマには、拡張機能コールバック・オブジェクトの具体的なクラスと、これらのオブジェクトを構成するのに必要なパラメーターへのスロットがあります。具体的なクラスはエクステンダーによって用意され、ホストで定義された所定のインターフェイスに適合する必要があります。実行時に、ホストは構成パラメーターに基づいて構成されたコールバック・オブジェクトをインスタンス化します。要約すると、Eclipseプラグインは拡張性において柔軟なモデルを提供し、疎結合されたコンポーネントからシステムを構成するための抽象的なアーキテクチャーは、ソフトウェア・システムで利用できるアーキテクチャー・パターンのレパートリーに重要なものとして加えられるということです([4]を参照)。サンプル・コードのインストールこの記事で取り上げたサンプルを実行し、そのソース・コードを見るには、Eclipseをインストールしたフォルダーにcompanionプラグインzipファイルを解凍してください。workbenchを通してサンプルと対話するには、以下に示すように、ユーザー・インターフェイス要素を有効にする必要があります拡張処理のデモ。Perspectiveメニューを選択して、ダイアログを開きます。Actionsを有効にしてから、ダイアログを閉じます。Demoメニューを利用できるようになります。Perspectiveメニューを選択して、ダイアログを開きます。Viewを有効にしてから、ダイアログを閉じます。Viewが表示されます。この項目を選択して、サンプル用のビューを表示します。Perspectiveメニューを選択して、ダイアログを開きます。Actionsを有効にしてから、ダイアログを閉じます。Listenerメニューを利用できるようになります。簡潔にするために、サンプルではメッセージ表示に標準出力と標準エラーを使用しています。デフォルトで、win32プラットフォーム上のEclipseはjavaw仮想マシーンを使用しますが、この仮想マシーンは、標準入出力に連結されたコンソールをもっていません。win32プラットフォーム上で、標準入出力に連結されたコンソールとともにEclipseを起動するには、以下に示すように、-vmオプションを使って、Eclipse実行イメージがjavawではなくjavaを使用することが求められます。1.3.1_02を使って動作確認されています。Group内のディスカッションから生まれました。Thistlethwaiteに感謝します。彼らとの創造力に富んだ会話が、この記事を執筆するきっかけになりました。非常に多くの提言が題材の内容と表現をよりよいものにしてくれました。Bialikに感謝します。レビューを中心にグループ・ディスカッションは編成されました。Estbergは、この記事で使用したパワー・ストリップ・メタファーに基づく拡張ポイントのダイアグラム表現を考案しました。Donには詳細なコメントをしてくれたことにも感謝します。Rivieresに感謝します。