インターフェースの継承:これについてどう思いますか:[終了]
-
08-07-2019 - |
質問
コードベースを確認すると、次のパターンに似た継承構造が見つかりました。
interface IBase
{
void Method1();
void Method2();
}
interface IInterface2 : IBase
{
void Method3();
}
class Class1 : IInterface2
{
...
}
class Class2 : IInterface2
{
...
}
class Class3 : IInterface2
{
...
}
Class2
では、 Method1
は NotImplementedException
をスローします。
質問:
- インターフェースの継承について一般的にどう思いますか?
-
IBase
とClass2
の関係は、リスコフ置換の原則に違反しますか?
解決
まあ、まず第一に、私は一般的にNotImplementedException例外をスローすることでインターフェースを実装することに反対です。基本的には、「このクラスは電卓としても機能します」と言っているようなものです。
しかし、場合によっては、「正しい方法」を実行する唯一の方法であるため、100%反対することはありません。
知っておくべきこと。
インターフェースはコントラクトであり、あなたがコントラクトに従うと言うインターフェースを実装することによって。その後、契約の一部を無効にし始めると、契約またはその実装が不十分に考えられたように思えます。
編集:グレッグビーチの答え:インターフェイスが具体的に実装はこれらの例外をスローする必要があり、それがコントラクトの一部であると言い、クラスがそれを完全に許可されていることに同意します。
置換の原則に関しては、状態は次のとおりです。
q(x)をT型のオブジェクトxについて証明可能なプロパティとします。その後、SがTのサブタイプであるS型のオブジェクトyに対してq(y)が真になる必要があります。
このコンテキストでは、子孫型でメソッドの動作を変更すると、基本クラスからメソッドをオーバーライドするのと同じくらい原則に違反します。
次の点のように、原理はウィキペディアのページでより詳細に説明されています(括弧と私のコメントの強調):
- サブクラスでは前提条件を強化できません。 (前提条件としては、「この時点でクラスがこのメソッドを呼び出す準備ができていること」)
- サブクラスでは事後条件を弱めることはできません。 (事後条件は、メソッドを呼び出した後、クラスの状態について何かが当てはまることです)
インターフェイスの完全なコントラクトを示していないため、コンパイラがチェックできる宣言部分のみであるため、その実装がnotの実装に当てはまるかどうかを知ることはできません。
たとえば、Method2に次の条件が関連付けられている場合:
- いつでも呼び出すことができます
- 一連のイベント内の次のイベントの準備ができるようにオブジェクトの状態を変更します
NotImplementedExceptionをスローすると、原則に違反します。
ただし、契約に次のようにも記載されている場合:
- イベントのチェーンをサポートしないクラスの場合、このメソッドはNotImplementedExceptionまたはNotSupportedExceptionをスローする必要があります
それではおそらくそうではありません。
他のヒント
だから、あなたが尋ねている質問は次のように仮定しています:
派生型がスローする場合 メソッドの
NotImplementedException
基本型ではない場合、これを行います リスコフ置換に違反する 原則。
これは、メソッドがその契約を履行するためにメソッドがこの例外をスローするかもしれないとインターフェースのドキュメントが言っているかどうかに依存すると思います。その場合、原則に違反しません。そうでない場合は違反します。
.NETフレームワークのこの古典的な例は、 Read
、 Write
、<などの一連の操作を含む Stream
クラスです。 code> Seek ただし、これらのすべての操作をサポートするストリームの要件はなく、 NotSupportedException
をスローできるように文書化されています。
あなたの意味を理解していると仮定すると、答えはイエスだと思います。インターフェースを継承することは問題ありません。いいえ、リスコフの代替原則に違反しません。
インターフェースについて考える方法は、「のように振る舞う」ことです。オペレーター。クラスが従うことを約束する一連の動作をメソッドなどで表現します。したがって、IEatsMiceインターフェースを継承するIBehavesLikeACatインターフェースを持つことに問題はありません。したがって、猫は両方を実装し、フェレットのみIEatsMiceを使用します。
まず、インターフェイスの継承は問題ありません。クラスの継承と同じ方法で適用され、非常に強力なツールです。
インターフェースは動作を説明します。インターフェースがクラスが「できること」を定義するとしましょう。したがって、宣言しているインターフェイスを実装する場合、そのインターフェイスが指定することを実行できます。例:
interface ISubmergible
{
void Submerge();
}
クラスがインターフェイスを実装している場合、クラスはサブマージできます。それにもかかわらず、一部のインターフェイスは他のインターフェイスを意味します。たとえば、このインターフェイスを想像してください
interface IRunner
{
void Run();
}
それは、それを実装するクラスが実行できることを示すインターフェースを定義しています...それにもかかわらず、プログラムのコンテキストでは、何かが実行できる場合は明らかに歩くことができると理解されているので、それが満たされていることを確認する必要があります:
interface IWalker
{
void Walk();
}
interface IRunner : IWalker
{
void Run();
}
最後に、NotImplementedException全体について...いくつかの提案に驚いています。 NotImplementedExceptionは、クラスのインターフェイスメソッドによって決して、発生することはありません。インターフェースを実装する場合、インターフェースが確立するコントラクトを明示的に受け入れ、NotImplementedExceptionを発生させると、基本的に&quot; ok、うそをつきました、インターフェースをサポートしたが、実際にはサポートしない&quot;と言っています。
インターフェースは、クラスが実装するものとしないものを心配する必要を避けるためのものです。あなたがそれを奪うならば、彼らは役に立たない。さらに重要なことは、あなたのチームの他のメンバーが理解できない場合でも、あなたの仲間はそのような行動を期待することです。それ。 したがって、class2は常識とインターフェイスの目的に違反します。 Class2はIBaseを実装しないため、主張しないでください。
NotSupportedExceptionのスローは問題ありません。これは、一部のインターフェイス機能が設計によって実装されていない場合にスローする例外です。
NotImplementedExceptionの場合はあまり明確ではありません。これは通常、まだ実装されていないが実装されるコードに使用されます。たとえば、Visual Studio 2008によって生成されたインターフェイス実装のスタブには、コード「&quot; throw new NotImplementedException()&quot;」が含まれています。
議論については、 Brad Abramのブログをご覧ください。これ。
インターフェイスの継承は、.Netフレームワークのいくつかの場所で使用されます。だからそこにすべてが完璧ではないが、これは大丈夫と思われると思う。たとえば、IEnumerableインターフェイスを見てください。
NotImplementedExceptionsのスローに関しては、コードでの使用方法によって異なります。たとえば、一部はオプションであるいくつかのメソッドでインターフェイスを定義できます。その場合、メソッドが使用可能かどうかを確認し、使用可能な場合にのみ使用する必要があります。