デフォルト/共有機能を備えたクラスがあります。私はabstract class
を使用しています:
public interface ITypeNameMapper
{
string Map(TypeDefinition typeDefinition);
}
public abstract class TypeNameMapper : ITypeNameMapper
{
public virtual string Map(TypeDefinition typeDefinition)
{
if (typeDefinition is ClassDefinition classDefinition)
{
return Map(classDefinition);
}
...
throw new ArgumentOutOfRangeException(nameof(typeDefinition));
}
protected abstract string Map(ClassDefinition classDefinition);
}
ご覧のとおり、私はITypeNameMapper
インターフェースも持っています。抽象クラスTypeNameMapper
またはabstract class
で十分であれば、このインターフェイスを定義しても意味がありますか?
この最小限の例のTypeDefinition
も抽象的です。
C# は、インターフェースを除いて多重継承を許可しないためです。
したがって、TypeNameMapperとSomethingelseMapperの両方であるクラスがある場合、次のことができます。
class MultiFunctionalClass : ITypeNameMapper, ISomethingelseMapper
{
private TypeNameMapper map1
private SomethingelseMapper map2
public string Map(TypeDefinition typeDefinition) { return map1.Map(typeDefintion);}
public string Map(OtherDef otherDef) { return map2.Map(orderDef); }
}
インターフェースと抽象クラスは異なる目的を果たします:
あなたの例では、interface ITypeNameMapper
はクライアントのニーズを定義し、abstract class TypeNameMapper
は値を追加していません。
質問に明確に答えたい場合、著者は「抽象クラスTypeNameMapperまたは抽象クラスがすでに十分にある場合、このインターフェイスを定義することは理にかなっていますか?」と述べています。
答えは「はい」と「いいえ」です。はい、抽象基本クラスがすでにある場合でもインターフェイスを作成する必要があります(クライアントコードで抽象基本クラスを参照してはならないため)。作成していないはずなので、いいえインターフェースがない場合の抽象基本クラス。
作成しようとしているAPIを十分に検討していないことは明らかです。最初にAPIを考え出し、必要に応じて部分的な実装を提供します。抽象基本クラスがコードで型チェックを行うという事実は、それが正しい抽象化ではないことを伝えるのに十分です。
OODのほとんどのことと同様に、溝にいてオブジェクトモデルを適切に実行すると、コードは次に何が起こるかを通知します。インターフェースから始めて、必要なクラスにそのインターフェースを実装します。同様のコードを書いている場合は、抽象基本クラスに抽出します。重要なのはインターフェースです。抽象基本クラスは単なるヘルパーであり、複数存在する場合があります。
インターフェースの概念全体は、共有APIを持つクラスのファミリーをサポートするために作成されました。
これは、インターフェイスを使用すると、その仕様の実装が複数存在する(または存在することが予想される)ことを意味します。
DIフレームワークは、実装が1つしかない場合でも、多くの場合インターフェースを必要とするという点で、水を濁らせています。私にとって、これは、ほとんどの場合、新しい呼び出しのより複雑で遅い手段にとっては不合理なオーバーヘッドですが、それはそれが何であるかです。
答えは質問自体にあります。抽象クラスがある場合は、共通のAPIを使用して複数の派生クラスを作成する準備をしています。したがって、インターフェースの使用が明確に示されます。