私の開発作業の繰り返しのテーマは、社内プラグインアーキテクチャの使用または作成です。構成ファイル(XML、.confなど)、継承フレームワーク、データベース情報、ライブラリなど、さまざまな方法でアプローチしているのを見てきました。私の経験では:
一緒に仕事をしたさまざまなアーキテクチャから学びたいと思っているので、私もコミュニティに提案を求めています。 SOLIDプラグインアーキテクチャをどのように実装しましたか?最悪の障害(またはこれまでに見た最悪の障害)は?新しいプラグインを実装する場合はどうしますか?アーキテクチャの面では、どのSDKまたはオープンソースプロジェクトで作業したのが、優れたアーキテクチャの最良の例ですか?
私が自分で見つけてきたいくつかの例:
これらの例は、さまざまな言語の長所を果たしているようです。優れたプラグインアーキテクチャは、必ずしも言語に関連付けられていますか?ツールを使用してプラグインアーキテクチャを作成するのが最善ですか、それとも自分の次のモデルでそれを行うのが最善ですか?
これは、答えではなく、潜在的に有用な発言/例の束ではありません。
アプリケーションを拡張可能にする効果的な方法の1つは、内部をスクリプト言語として公開し、その言語ですべてのトップレベルのものを記述することです。これにより、非常に変更可能になり、実質的に将来の証明になります(プリミティブが適切に選択され実装されている場合)。この種の成功例はEmacsです。機能を拡張したい場合、APIを学習したり、別のプラグインを作成/コンパイルする必要がないので、Eclipseスタイルのプラグインシステムよりもこれを好みます。現在のバッファー自体に3行のスニペットを記述し、評価して使用することができます。非常に滑らかな学習曲線と非常に楽しい結果。
私が少し拡張したアプリケーションの1つは、 Trac です。コンポーネントアーキテクチャがあり、この状況では、タスクは拡張ポイントをアドバタイズするモジュールに委任されます。次に、これらのポイントに収まり、フローを変更する他のコンポーネントを実装できます。上記のKalkieの提案に少し似ています。
もう1つ良いのは、 py.test です。 「最高のAPIはAPIなし」という哲学に従っており、純粋にあらゆるレベルで呼び出されるフックに依存しています。規約に従って名前が付けられたファイル/関数でこれらのフックをオーバーライドし、動作を変更できます。サイト上のプラグインのリストを参照して、プラグインの実装の速さを確認してください。
いくつかの一般的なポイント。
私の経験では、実際には2種類のプラグインアーキテクチャがあります。
Eclipse model
これは、自由を可能にするためのものであり、無制限です。narrow API
は、プラグインが特定の機能を満たすためです。別の言い方をすれば、1つはプラグインによるアプリケーションへのアクセスを許可し、もう1つはアプリケーションによるアクセスを許可しますプラグイン。
区別は微妙であり、場合によっては区別がありません...アプリケーションの両方に必要です。
私は、Eclipse /プラグインモデルへのアプリのオープンに関する豊富な経験はありません(Kalkieの投稿の記事は素晴らしいです)。 Eclipseの処理方法について少し読みましたが、それ以上のものはありません。
Yeggeの properties blog では、プロパティパターンを使用してプラグインと拡張性を実現する方法について少し説明しています。
私が行ったほとんどの作業では、プラグインアーキテクチャを使用して、アプリがプラグイン(時間/表示/マップデータなど)にアクセスできるようにしました。
何年も前に、私はすべてを管理するためにファクトリー、プラグインマネージャー、設定ファイルを作成し、実行時に使用するプラグインを決定しました。
DI framework
その作業の大部分を行います。サードパーティのライブラリを使用するためにアダプタを記述する必要がありますが、通常はそれほど悪くはありません。
私が見た中で最高のプラグインアーキテクチャの1つは、Eclipseに実装されています。プラグインモデルを備えたアプリケーションではなく、すべてがプラグインです。基本アプリケーション自体はプラグインフレームワークです。
http://www.Eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html
私はかつて、各顧客がシステムをセットアップできるように非常に柔軟でなければならないプロジェクトに取り組みましたが、私たちが見つけた唯一の良い設計は顧客にC#コンパイラを出荷することでした!
仕様が次のような単語で満たされている場合:
私の経験のように、システムをどのようにサポートするか(および各顧客が通常のケースであり、プラグインを必要としないと考えるため、どのようにサポートに課金されるか)について多くの質問をします。
プラグインを作成する顧客(または専用のサポート担当者)のサポートは、アーキテクチャよりもはるかに困難です。
過去に使用したかなり単純な手法について説明します。このアプローチでは、C#リフレクションを使用して、プラグインの読み込みプロセスを支援します。この手法は変更できるため、C++に適用できますが、リフレクションを使用できるという利便性が失われます。
IPlugin
インターフェイスは、プラグインを実装するクラスを識別するために使用されます。アプリケーションがプラグインと通信できるようにするためのメソッドがインターフェースに追加されます。たとえば、アプリケーションがプラグインに初期化を指示するために使用するInit
メソッド。
プラグインを見つけるために、アプリケーションは.Netアセンブリのプラグインフォルダーをスキャンします。各アセンブリがロードされます。リフレクションは、IPlugin
を実装するクラスのスキャンに使用されます。各プラグインクラスのインスタンスが作成されます。
(または、Xmlファイルにロードするアセンブリとクラスがリストされている場合があります。これによりパフォーマンスが向上する場合がありますが、パフォーマンスの問題は見つかりませんでした)。
Init
メソッドは、各プラグインオブジェクトに対して呼び出されます。アプリケーションインターフェイスを実装するオブジェクトへの参照が渡されます:IApplication
(またはアプリに固有の名前、たとえばITextEditorApplication)。
IApplication
には、プラグインがアプリケーションと通信できるようにするメソッドが含まれています。たとえば、テキストエディタを記述している場合、このインターフェイスには、プラグインが現在開いているドキュメントのコレクションを列挙できるようにするOpenDocuments
プロパティがあります。
このプラグインシステムは、LuaPlugin
関数とアプリケーションインターフェイスをLuaスクリプトに転送するIPlugin
などの派生プラグインクラスを作成することにより、Luaなどのスクリプト言語に拡張できます。
この手法により、開発中にIPlugin
、IApplication
およびその他のアプリケーション固有のインターフェイスを繰り返し実装できます。アプリケーションが完成し、適切にリファクタリングされたら、公開されたインターフェイスを文書化できます。ユーザーが独自のプラグインを作成できるNiceシステムが必要です。
通常、MEFを使用します。 Managed Extensibility Framework(または略してMEF)は、拡張可能なアプリケーションの作成を簡素化します。 MEFは、アプリケーション拡張機能をロードするために活用できる検出および構成機能を提供します。
興味のある方は more ... を読んでください
私の経験では、柔軟なプラグインアーキテクチャを作成する2つの最良の方法は、スクリプト言語とライブラリです。私の考えでは、これらの2つの概念は直交しています。この2つは、関数型プログラミングやオブジェクト指向プログラミングのように、任意の割合で混在させることができますが、バランスを取ると最大の強みが得られます。通常、ライブラリは、動的機能を使用して特定のinterfaceを実現しますが、スクリプトは、動的インターフェイスを使用してfunctionalityを強調する傾向があります。
スクリプト管理ライブラリに基づいたアーキテクチャが最適に動作するようだとわかりました。スクリプト言語を使用すると、低レベルのライブラリを高レベルで操作できるため、ライブラリは特定のインターフェイスから解放され、アプリケーションレベルの対話はすべて、より柔軟なスクリプトシステムに委ねられます。
これが機能するには、スクリプトシステムに、アプリケーションデータ、ロジック、GUIへのフック、およびライブラリからのコードのインポートと実行の基本機能を備えた、かなり堅牢なAPIが必要です。さらに、スクリプトは通常、アプリケーションが適切に記述されていないスクリプトから正常に回復できるという意味で、safeである必要があります。スクリプトシステムを間接層として使用することは、Something Bad™の場合にアプリケーションがより簡単にデタッチできることを意味します。
プラグインをパッケージ化する方法は、個人の好みに大きく依存しますが、シンプルなインターフェースを備えた圧縮アーカイブ、例えばPluginName.ext
ルートディレクトリ。
「どのコンポーネントがプラグインになると予想されますか?」という質問に最初に答える必要があると思います。この数を絶対最小値または爆発をテストする必要がある組み合わせの数に維持する必要があります。プラグイン機能からコア製品(柔軟性が高すぎてはならない)を分離するようにしてください。
IOC(Inversion of Control)プリンシパル(read springframework)プリンシパルは柔軟なベースを提供するのにうまく機能することがわかりました。