1. ホーム
  2. c#

[解決済み] C#のクラスライブラリを設計するとき、どのような場合にインターフェイスではなく継承を選ぶべきですか?[クローズド]

2023-05-20 13:59:05

質問

私は、番号 Processor クラスがありますが、これらは 2 つの非常に異なることを行いますが、共通のコードから呼び出されます ("制御の逆転" の状況)。

を継承するかどうかを決定する際に、どのような設計上の考慮事項を認識する必要があるのか疑問に思っています。 BaseProcessor を実装するか、あるいは IProcessor をインターフェースとして実装します。

どのように解決するのですか?

一般的には、次のようなルールがあります。

  • 継承は です。 の関係を記述します。
  • インターフェースを実装することで できる の関係を記述します。

これをやや具体的に説明するために、例を見てみましょう。その System.Drawing.Bitmap クラス 画像です (そして、そのような画像は Image クラスを継承しています)、また できる のディスポーザブルを実装しているので IDisposable インターフェースを実装しています。また できる シリアライゼーションも実装しているので ISerializable インターフェイスを実装しています。

しかし、より現実的には、インターフェースはC#で多重継承をシミュレートするためによく使われます。もし、あなたの Processor のようなクラスから継承する必要がある場合 System.ComponentModel.Component のようなものを継承する必要がある場合は、ほとんど選択肢はありません。 IProcessor インターフェースを実装するしかないでしょう。

実際、インターフェースも抽象基底クラスも、特定のクラスが何ができるかを指定する契約を提供します。この契約を宣言するためにインターフェイスが必要であるというのはよくある俗説ですが、それは正しくありません。私が考える最大の利点は、抽象基底クラスによって、サブクラスにデフォルトの機能を提供することができることです。しかし、もし意味のあるデフォルトの機能がないのであれば、そのメソッド自体を abstract としてマークし、派生クラスがインターフェイスを実装する場合と同じように、自分自身でそれを実装することを要求することを妨げるものは何もありません。

このような質問に対する答えとして、私はしばしば .NET フレームワーク設計ガイドライン このガイドラインには、クラスとインターフェースのどちらを選択するかについて、次のように書かれています。

一般的に、クラスは抽象化されたものを公開するのに適した構造です。

インターフェイスの主な欠点は、APIの進化を可能にすることに関して、クラスよりもはるかに柔軟性に欠けることです。一度インターフェイスを出荷すると、そのメンバーのセットは永遠に固定されます。インターフェイスへのいかなる追加も、そのインターフェイスを実装している既存の型を壊してしまうでしょう。

クラスはより柔軟性を提供します。すでに出荷したクラスにメンバを追加することができます。メソッドが抽象的でない限り(つまり、メソッドのデフォルトの実装を提供する限り)、既存の派生クラスは変更されずに機能を継続します。

[ . . . ]

インターフェイスを支持する最も一般的な主張の1つは、インターフェイスによって契約と実装を分離することができるというものです。しかし、この主張は、クラスを使ってコントラクトと実装を分離することができないことを誤って想定しています。抽象クラスは、その具体的な実装とは別のアセンブリに存在し、そのような分離を達成するための素晴らしい方法です。

彼らの一般的な推奨事項は以下のとおりです。

  • する は、インターフェースよりもクラスの定義に賛成します。
  • する 実装からコントラクトを切り離すために、インターフェースの代わりに抽象クラスを使用します。抽象クラスは、正しく定義されていれば、コントラクトと実装の間のデカップリングを同じ程度にすることができます。
  • する。 値の型の多相性階層を提供する必要がある場合、インターフェイスを定義します。
  • を考慮する。 多重継承と同様の効果を得るためにインターフェイスを定義すること。

Chris Andersonはこの最後の信条に特に同意を示し、次のように主張しています。

抽象的な型は、より良いバージョンを提供し、将来の拡張性を可能にしますが、同時に唯一無二の基本型を焼くことになります。インターフェイスは、2 つのオブジェクトの間で、時間とともに変化する契約を本当に定義している場合に適しています。抽象的な基本型は、型のファミリーのための共通のベースを定義するのに適しています。