4

コードベースを確認したところ、次のパターンに似た継承構造が見つかりました。

interface IBase
{
    void Method1();
    void Method2();
}

interface IInterface2 : IBase
{
    void Method3();
}

class Class1 : IInterface2
{
    ...
}

class Class2 : IInterface2
{
    ...
}

class Class3 : IInterface2
{ 
    ...
}

Class2Method1スローしNotImplementedExceptionます。

質問:

  • インターフェイスの継承について一般的にどう思いますか?
  • リスコフの置換原則IBaseとの関係はありますか?Class2
4

6 に答える 6

10

まず第一に、私は一般的にNotImplementedException例外をスローすることによってインターフェースを実装することに反対しています。基本的には「まあ、このクラスは電卓としても機能しますよね」と言っているようなものです。

しかし、場合によっては、それが「正しい方法」で何かを行う唯一の方法であるため、私はそれに100%反対しているわけではありません。

知っておくべきことです。

インターフェースは契約であり、契約を順守すると言うインターフェースを実装することによって。それからあなたが契約の一部を否定し始めるならば、それは契約、またはそれの実行がよく考えられていなかったように私には聞こえます。


編集Greg Beechの答えを確認した後:実装がこれらの例外をスローする必要があるとインターフェイスが具体的に示している場合、それはコントラクトの一部であり、クラスがそれを完全に許可されていることに同意します。


置換原則に関しては、次のように述べられています。

q(x)をタイプTのオブジェクトxについて証明可能なプロパティとします。次に、タイプSのオブジェクトyに対してq(y)が真である必要があります。ここで、SはTのサブタイプです。

このコンテキストでは、子孫型でメソッドが行うことを変更すると、基本クラスからメソッドをオーバーライドするのと同じように、原則に違反します。

原則は、次の点のように、ウィキペディアのページでより詳細に説明されています(括弧と私のコメントの強調):

  • サブクラスで前提条件を強化することはできません。(前提条件は、「クラスはこの時点でこのメソッドを呼び出す準備ができている」ということです)
  • サブクラスで事後条件を弱めることはできません。(事後条件は、メソッドを呼び出した後、クラスの状態について何かが真であるということである可能性があります)

インターフェイスの完全なコントラクトを示しておらず、コンパイラがチェックできる宣言部分のみを示しているため、notの実装に原則が当てはまるかどうかを知ることは不可能です。

たとえば、Method2に次の条件が関連付けられている場合:

  • いつでも呼び出すことができます
  • イベントのチェーン内の次のイベントの準備ができるようにオブジェクトの状態を変更します

次に、NotImplementedExceptionをスローすると、原則に違反します。

ただし、契約に次のようにも記載されている場合:

  • イベントのチェーンをサポートしないクラスの場合、このメソッドはNotImplementedExceptionまたはNotSupportedExceptionをスローする必要があります

それならおそらくそうではありません。

于 2008-11-21T08:12:54.567 に答える
4

だから、あなたが求めている質問は次のとおりだと思います:

NotImplementedException基本型がスローしないメソッドに対して派生型が をスローする場合、 これは Liskov の置換原則に違反しますか。

それは、メソッドが契約を履行するためにこの例外をスローする可能性があるとインターフェイスのドキュメントに記載されているかどうかによって異なります。もしそうなら、それは原則に違反しません、そうでなければ違反します。

.NET フレームワークにおけるこれの古典的な例は、 などの一連の操作をStream持つクラスですが、ストリームがこれらの操作のすべてをサポートする必要はなく、 をスローできると文書化されています。ReadWriteSeekNotSupportedException

于 2008-11-21T08:28:28.297 に答える
1

NotSupportedException のスローは問題ありません。これは、一部のインターフェイス機能が設計によって実装されていない場合にスローされる例外です。

NotImplementedException についてはあまり明確ではありません。これは通常、まだ実装されていないが、実装される予定のコードに使用されます。たとえば、Visual Studio 2008 によって生成されたインターフェイス実装のスタブには、「throw new NotImplementedException()」というコードが含まれています。

これに関する議論については、Brad Abram のブログを参照してください。

于 2008-11-21T10:22:17.363 に答える
1

私があなたの言いたいことを理解していると仮定すると、答えはイエスだと思います。インターフェイスの継承は問題ありません。ノーです。リスコフの置換原則に違反していません。

インターフェースの考え方は、「のように振る舞う」演算子です。クラスが従うことを約束し、メソッドなどによって表現される一連の動作を記述します。したがって、IEatsMice インターフェイスから継承する IBehavesLikeACat インターフェイスを持つことに問題はありません。猫のように動作する場合、明らかにマウスを食べます。したがって、猫は両方を実装し、フェレットは IEatsMice のみを実装します。

于 2008-11-21T08:33:04.230 に答える
1

まず第一に、インターフェイスの継承は問題ありません。クラスの継承と同じように適用でき、非常に強力なツールです。

インターフェイスは動作を記述します。たとえば、クラスが「できる」ことをインターフェイスが定義しているとしましょう。したがって、宣言しているインターフェイスを実装すると、そのインターフェイスが指定することを実行できます。例えば:

interface ISubmergible
{
  void Submerge();
}

そのため、クラスがインターフェイスを実装している場合、それは沈没する可能性があることは明らかです。それにもかかわらず、一部のインターフェースは他のインターフェースを暗示しています。たとえば、このインターフェースを想像してみてください。

interface IRunner
{
  void Run();
}

これは、それを実装するクラスが実行できることを示すインターフェイスを定義します...それでも、プログラムのコンテキストでは、何かを実行できる場合は明らかに歩くことができるため、それが満たされていることを確認する必要があります。

interface IWalker
{
  void Walk();
}

interface IRunner : IWalker
{
  void Run();
}

最後に、NotImplementedException 全体について...いくつかの提案に驚いています。クラスのインターフェイス メソッドによってNotImplementedException が発生することは決してありません。インターフェイスを実装する場合、インターフェイスが確立する契約を明示的に受け入れている場合、NotImplementedException を発生させた場合、基本的には「わかりました。嘘をつきました。インターフェイスをサポートしていると言いましたが、実際にはサポートしていません」と言っています。

インターフェースは、クラスが何を実装し、何を実装しないかについて心配する必要がないようにするためのものです。それを取り除けば、彼らは役に立たない。さらに重要なことは、たとえあなたが自分のしていることを理解しているとしても、あなたの仲間はそのような行動を期待するでしょう。たとえあなたが何をしているかを理解していても、チームの他のメンバーはそうではなく、あなたでさえ、今から 6 か月後にはその背後にあるロジックを理解していないでしょう。したがって、class2 は常識とインターフェイスの目的に違反しています。Class2 は IBase を実装していないため、実装していると主張しないでください。

于 2008-11-21T09:18:27.603 に答える
0

インターフェイスの継承は、.Net フレームワークのいくつかの場所で使用されます。そこにあるすべてが完璧というわけではありませんが、これは問題ないと見なされていると思います。たとえば、IEnumerable インターフェイスを見てください。

NotImplementedExceptions をスローすることに関しては、コードでそれらをどのように使用するかによって異なります。たとえば、一部がオプションであるいくつかのメソッドを使用してインターフェイスを定義できます。その場合、メソッドが利用可能かどうかを確認し、利用可能な場合にのみ使用する必要があります。

于 2008-11-21T08:44:54.347 に答える