[解決済み] C#のクラスライブラリを設計するとき、どのような場合にインターフェイスではなく継承を選ぶべきですか?[クローズド]
質問
私は、番号
Processor
クラスがありますが、これらは 2 つの非常に異なることを行いますが、共通のコードから呼び出されます ("制御の逆転" の状況)。
を継承するかどうかを決定する際に、どのような設計上の考慮事項を認識する必要があるのか疑問に思っています。
BaseProcessor
を実装するか、あるいは
IProcessor
をインターフェースとして実装します。
どのように解決するのですか?
一般的には、次のようなルールがあります。
- 継承は です。 の関係を記述します。
- インターフェースを実装することで できる の関係を記述します。
これをやや具体的に説明するために、例を見てみましょう。その
System.Drawing.Bitmap
クラス
は
画像です (そして、そのような画像は
Image
クラスを継承しています)、また
できる
のディスポーザブルを実装しているので
IDisposable
インターフェースを実装しています。また
できる
シリアライゼーションも実装しているので
ISerializable
インターフェイスを実装しています。
しかし、より現実的には、インターフェースはC#で多重継承をシミュレートするためによく使われます。もし、あなたの
Processor
のようなクラスから継承する必要がある場合
System.ComponentModel.Component
のようなものを継承する必要がある場合は、ほとんど選択肢はありません。
IProcessor
インターフェースを実装するしかないでしょう。
実際、インターフェースも抽象基底クラスも、特定のクラスが何ができるかを指定する契約を提供します。この契約を宣言するためにインターフェイスが必要であるというのはよくある俗説ですが、それは正しくありません。私が考える最大の利点は、抽象基底クラスによって、サブクラスにデフォルトの機能を提供することができることです。しかし、もし意味のあるデフォルトの機能がないのであれば、そのメソッド自体を
abstract
としてマークし、派生クラスがインターフェイスを実装する場合と同じように、自分自身でそれを実装することを要求することを妨げるものは何もありません。
このような質問に対する答えとして、私はしばしば .NET フレームワーク設計ガイドライン このガイドラインには、クラスとインターフェースのどちらを選択するかについて、次のように書かれています。
一般的に、クラスは抽象化されたものを公開するのに適した構造です。
インターフェイスの主な欠点は、APIの進化を可能にすることに関して、クラスよりもはるかに柔軟性に欠けることです。一度インターフェイスを出荷すると、そのメンバーのセットは永遠に固定されます。インターフェイスへのいかなる追加も、そのインターフェイスを実装している既存の型を壊してしまうでしょう。
クラスはより柔軟性を提供します。すでに出荷したクラスにメンバを追加することができます。メソッドが抽象的でない限り(つまり、メソッドのデフォルトの実装を提供する限り)、既存の派生クラスは変更されずに機能を継続します。
[ . . . ]
インターフェイスを支持する最も一般的な主張の1つは、インターフェイスによって契約と実装を分離することができるというものです。しかし、この主張は、クラスを使ってコントラクトと実装を分離することができないことを誤って想定しています。抽象クラスは、その具体的な実装とは別のアセンブリに存在し、そのような分離を達成するための素晴らしい方法です。
彼らの一般的な推奨事項は以下のとおりです。
- する は、インターフェースよりもクラスの定義に賛成します。
- する 実装からコントラクトを切り離すために、インターフェースの代わりに抽象クラスを使用します。抽象クラスは、正しく定義されていれば、コントラクトと実装の間のデカップリングを同じ程度にすることができます。
- する。 値の型の多相性階層を提供する必要がある場合、インターフェイスを定義します。
- を考慮する。 多重継承と同様の効果を得るためにインターフェイスを定義すること。
Chris Andersonはこの最後の信条に特に同意を示し、次のように主張しています。
抽象的な型は、より良いバージョンを提供し、将来の拡張性を可能にしますが、同時に唯一無二の基本型を焼くことになります。インターフェイスは、2 つのオブジェクトの間で、時間とともに変化する契約を本当に定義している場合に適しています。抽象的な基本型は、型のファミリーのための共通のベースを定義するのに適しています。
関連
-
[解決済み] エンティティタイプ <type> は、現在のコンテキストのモデルの一部ではありません。
-
[解決済み】OnCollisionEnter2Dが実行されない?
-
[解決済み】スレッド終了またはアプリケーションの要求により、I/O操作が中断されました。
-
[解決済み] どのような場合に '$this' よりも 'self' を使うべきですか?
-
[解決済み] インターフェースと抽象クラスの違いは何ですか?
-
[解決済み] なぜList<T>を継承しないのですか?
-
[解決済み] インターフェースと抽象クラス(一般的なOO)
-
[解決済み] C++でクラスと構造体はいつ使い分けるべきか?
-
[解決済み] インターフェースとベースクラス
-
[解決済み] Javaインターフェースでスタティックメソッドを定義できないのはなぜですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】文字列が有効な DateTime " format dd/MM/yyyy " として認識されなかった。
-
解決済み] Critical error detected c0000374 - C++ dll returns pointer off allocated memory to C# [解決済み] Critical error detected c0000374 - C++ dll returns pointer off allocated memory to C#.
-
[解決済み】「...は'型'であり、与えられたコンテキストでは有効ではありません」を解決するにはどうすればよいですか?(C#)
-
[解決済み】ファイルへの読み書きの際に共有違反のIOExceptionが発生する C#
-
[解決済み】 C# 条件演算子エラー 代入、call、increment、decrement、await、new object 式のみ文として使用可能です。
-
[解決済み】「namespace」なのに「type」のように使われる。
-
[解決済み】プロセスが実行されているかどうかを知るには?
-
[解決済み】データが存在しないのに読み込もうとする試みが無効である
-
[解決済み] インターフェースとベースクラス
-
[解決済み] インターフェースと抽象クラス [重複]の比較