ここで重要なのは、JavaとC#の小さな違いの1つです。Javaでは、すべてのメンバーはデフォルトで仮想です。C#では、すべてのメンバーはデフォルトでシールされます-インターフェイスメンバーを除きます。
これに伴う仮定はガイドラインに影響します。Javaでは、リスコフの置換原則[1]に従って、すべてのパブリックタイプを非最終と見なす必要があります。実装が1つしかない場合は、クラスに名前を付けますParser
。複数の実装が必要な場合は、クラスを同じ名前のインターフェイスに変更し、具体的な実装をわかりやすい名前に変更します。
C#では、クラスを取得するとき(名前がで始まらないI
)、それが目的のクラスであるという主な仮定です。念のため、これは100%近い精度ではありません-典型的な反例はStream
(実際にはインターフェイスまたはいくつかのインターフェイスであるはずの)クラスであり、誰もが他の言語からの独自のガイドラインと背景を持っています。かなり広く使われているような他の例外もありますBase
抽象クラスを意味する接尾辞は-ちょうどインタフェースと同じように、あなたが知っているタイプが多型であることを想定しています。
インターフェイスを抽象クラスにすることに頼ることなく、そのインターフェイスに関連する機能の非接頭辞付きの名前を残す便利な機能もあります(C#にはクラスの多重継承がないために傷つきます)。これはIEnumerable<T>
、インターフェイスEnumerable
として、およびそのインターフェイスに適用されるメソッドのリポジトリとして使用するLINQによって普及しました。これは、インターフェイスにメソッド実装を含めることができるJavaでは不要です。
最終的に、I
プレフィックスはC#の世界で広く使用され、拡張により、.NETの世界(.NETコードのほとんどがC#で記述されているため、ほとんどのパブリックインターフェイスでC#のガイドラインに従うことが理にかなっています)。これは、この表記法に従うライブラリとコードをほぼ確実に使用することを意味し、不要な混乱を防ぐために伝統を採用することは理にかなっています-プレフィックスを省略するとコードが良くなるというわけではありません:)
ボブおじさんの推論は次のようなものだったと思います。
IBanana
バナナの抽象的な概念です。実装クラスの名前がの場合よりも優れている可能性がある場合Banana
、抽象化はまったく意味がないため、インターフェイスを削除してクラスを使用する必要があります。より良い名前(たとえば、LongBanana
またはAppleBanana
)がある場合Banana
、インターフェイスの名前として使用しない理由はありません。したがって、I
プレフィックスを使用することは、無駄な抽象化があることを意味します。これにより、コードが理解しにくくなり、メリットがありません。また、厳密なOOPを使用すると、常にインターフェイスに対してコードI
が作成されるため、型のプレフィックスが表示されない唯一の場所は、コンストラクターになります-非常に無意味なノイズです。
これをサンプルIParser
インターフェイスに適用すると、抽象化が完全に「意味のない」領域にあることが明確にわかります。どちらのパーサ(例えばの具体的な実装についての具体的な何かがあるのですJsonParser
、XmlParser
、...)、またはあなただけのクラスを使用する必要がありますが。特定の実装がある場合、または「デフォルト」の抽象クラスまたは拡張メソッドが必要な場合は、「デフォルト実装」(一部の環境ではこれが実際に意味をなしますが、特にCOM)はありません。ただし、C#では、コードベースで既に-prefixが省略されていない限りI
、そのままにしてください。次のようなコードが表示されるたびにメンタルノートを作成するだけです。class Something: ISomething
つまり、誰かがYAGNIをフォローし、合理的な抽象化を構築するのが得意ではないということです。
[1]-技術的には、これはリスコフの論文では特に言及されていませんが、元のOOP論文の基礎の1つであり、リスコフの私の読書では、彼女はこれに挑戦しませんでした。それほど厳密ではない解釈(ほとんどのOOP言語で採用されている解釈)では、これは、置換(つまり、非最終/密閉)を目的とするパブリック型を使用するコードは、その型の準拠実装で動作する必要があることを意味します。