.NET アプリケーションにプラグイン サポートを追加しています。基本クラスは私には理にかなっているように思えるので、人々はそれを継承して特定の呼び出しをオーバーライドしたり、デフォルトの機能を維持したり、いくつかの内部ヘルパー関数を使用したりできます。
継承するベース プラグイン クラスではなくインターフェイスを選択するのはなぜですか? どのデザインを選ぶべきか、またその理由を教えていただけますか?
.NET アプリケーションにプラグイン サポートを追加しています。基本クラスは私には理にかなっているように思えるので、人々はそれを継承して特定の呼び出しをオーバーライドしたり、デフォルトの機能を維持したり、いくつかの内部ヘルパー関数を使用したりできます。
継承するベース プラグイン クラスではなくインターフェイスを選択するのはなぜですか? どのデザインを選ぶべきか、またその理由を教えていただけますか?
System.Addin (MAF) 名前空間または Managed Extensibility Framework (MEF) を検討する必要があります。MEF は、MAF よりもはるかに単純であるため、まだプレリリースですが、推奨される選択肢です。これらのいずれかを選択すると、アドインをロードして操作するために必要な多くの配管作業が簡素化されます。
インターフェイスと抽象クラスの間で選択を行う限り、MAF または MEF を使用する場合、その一部は自動的に作成されます。このコンテキストにおける最も基本的な違いは、抽象基本クラスを提供することにより、カスタム プラグイン (あなたまたは他の開発者によって作成されたもの) の継承ポイントを提供し、特定のメソッド/プロパティがデフォルトの動作を提供し、派生クラスに特定の実装を強制することです。必要なメソッド/プロパティ。欠点は、単一の基本クラスに制限されることです。
インターフェイスは、単一の基本クラスの制限を回避し、カスタム プラグインに継承ポイントを提供し、特定のメソッド/プロパティが実装されていることを保証しますが、既定の動作を提供することはできません。また、抽象クラスは抽象または仮想の非パブリック メンバー (通常は保護) を持つことができますが、インターフェイスでパブリック メンバー以外のものを指定することはできません。
プラグインコントラクトのインターフェースを使用します。特定のタイプのプラグインが特定の機能を共有している可能性がある場合は、インターフェイスを実装する抽象基本クラスを作成します。また、契約が実際のアプリケーションの外部のアセンブリに含まれていることを確認してください。
.NETでは、多重継承がないことに注意してください。実装者に少しの機能を提供するために継承スロットを放棄するように要求することは、良い考えではありません。
なぜそれがどちらかでなければならないのですか?
プラグインが従わなければならない契約を、どこでも参照されるインターフェースとして定義できます。
さらに、そのインターフェイスを実装する基本クラスを定義することもできますが、デフォルトの実装を提供できない一部のインターフェイス関数に対して呼び出される抽象メソッドしかありません。
public interface IPlugin
{
void Initialize ();
void Stuff ();
}
public class PluginBase : IPlugin
{
protected abstract DoInitialize ();
protected abstract DoStuff ();
void IPlugin.Initialize { this.DoInitialize (); }
void IPlugin.Stuff { this.DoStuff (); }
}
このトピックに関する良い投稿がここにあります: プラグインAPIの設計
私は個人的にインターフェースを使用し、プラグインにすべての詳細を実装させます。
プラグインに、処理したい個々のイベントのコールバック(委任)を登録させることは、当然のことだと思います。これは、ほとんどのフレームワークが.netで機能する方法です。
言い換えれば、基本クラスもインターフェースもありません。このソリューションの利点は、プラグインが特定の外部インターフェイスまたは基本クラスに準拠する必要がなく、必要な機能を登録するだけであるということです。
例として、任意のasp.netコントロールの「イベント」セクションは次のように実行します。UserControlを見てください
誰もが言及するのを忘れているのは、下位互換性です。既存のクライアントに影響を与えずに既存のインターフェイスを変更することはできませんが、既存のクライアントを壊すことなく基本クラスに新しいメソッドを追加できます。
インターフェイスとの互換性の問題を回避するための代替手段があります。たとえば、アプリケーションに新しい拡張機能を含める場合、古いインターフェイスを継承する新しいインターフェイスを作成できます。ただし、これには、IClientInterfaceV2 や IClientInterfaceV3 などの型でアーキテクチャが肥大化するという欠点があります。
私の個人的な提案は、 scwagnerによって提案されたようなアプローチを採用し、基本クラスとインターフェイスの両方を作成することです。また、将来のバージョンでは実装が壊れる可能性があること、および将来の互換性の問題を回避するために基本クラスの継承戦略が推奨されることを示す、インターフェイス ユーザーへの警告を含めます。