私にとっては、汎用のNamedEntityに依存するのではなく、クラスに具体的な名前を付けるため、これは理にかなっています。一方、追加のプロパティを持たないクラスは数多くあります。
このアプローチには欠点がありますか?
アプローチは悪くありませんが、利用可能なより良いソリューションがあります。要するに、インターフェイスはこのためのはるかに優れたソリューションです。ここでインターフェイスと継承が異なる主な理由は、1つのクラスからしか継承できないが、多くのインターフェイスを実装できるためです。
たとえば、名前付きエンティティと監査済みエンティティがあるとします。いくつかのエンティティがあります:
One
監査対象エンティティでも名前付きエンティティでもありません。それは簡単です:
public class One
{ }
Two
は名前付きエンティティですが、監査対象エンティティではありません。それは本質的にあなたが今持っているものです:
public class NamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Two : NamedEntity
{ }
Three
名前付きエントリと監査済みエントリの両方です。ここで問題が発生します。AuditedEntity
基本クラスを作成できますが、との両方をThree
継承させることはできません: AuditedEntity
NamedEntity
public class AuditedEntity
{
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}
public class Three : NamedEntity, AuditedEntity // <-- Compiler error!
{ }
ただし、AuditedEntity
から継承することで回避策を考えることができますNamedEntity
。これは、すべてのクラスが他の1つのクラスから(直接)継承するだけで済むことを保証する巧妙なハックです。
public class AuditedEntity : NamedEntity
{
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}
public class Three : AuditedEntity
{ }
これでも機能します。しかし、ここで行ったことは、すべての監査対象エンティティが本質的に名前付きエンティティでもあると述べています。これで最後の例になります。Four
は監査対象エンティティですが、名前付きエンティティではありません。しかし、あなたは任せることはできないFour
から継承しAuditedEntity
ますが、その後もそれを作ることになるようNamedEntity
AuditedEntity間の継承のためにand
NamedEntity`。
継承を使用するThree
と、Four
クラスの複製を開始しない限り、両方を作成して動作させる方法はありません(これにより、まったく新しい問題が発生します)。
インターフェイスを使用すると、これを簡単に実現できます。
public interface INamedEntity
{
int Id { get; set; }
string Name { get; set; }
}
public interface IAuditedEntity
{
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}
public class One
{ }
public class Two : INamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Three : INamedEntity, IAuditedEntity
{
public int Id { get; set; }
public string Name { get; set; }
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}
public class Four : IAuditedEntity
{
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}
ここでの唯一の小さな欠点は、まだインターフェイスを実装する必要があることです。ただし、特定のエンティティに対して複数の一般的なタイプのバリエーションが必要な場合に生じる欠点を伴わずに、共通の再利用可能なタイプを持つことですべての利点を得ることができます。
ただし、ポリモーフィズムはそのまま残ります。
var one = new One();
var two = new Two();
var three = new Three();
var four = new Four();
public void HandleNamedEntity(INamedEntity namedEntity) {}
public void HandleAuditedEntity(IAuditedEntity auditedEntity) {}
HandleNamedEntity(one); //Error - not a named entity
HandleNamedEntity(two);
HandleNamedEntity(three);
HandleNamedEntity(four); //Error - not a named entity
HandleAuditedEntity(one); //Error - not an audited entity
HandleAuditedEntity(two); //Error - not an audited entity
HandleAuditedEntity(three);
HandleAuditedEntity(four);
一方、追加のプロパティを持たないクラスは数多くあります。
これはマーカーインターフェイスパターンのバリエーションで、空のインターフェイスを実装して、インターフェイスタイプを使用して、特定のクラスがこのインターフェイスで「マーク」されているかどうかを確認できるようにします。
実装されたインターフェースの代わりに継承されたクラスを使用していますが、目標は同じであるため、「マークされたクラス」と呼びます。
額面通り、マーカーインターフェイス/クラスに問題はありません。それらは構文的および技術的に有効であり、マーカーが(コンパイル時に)普遍的に条件付きではなく真である限り、それらの使用に固有の欠点はありません。
これは、例外が実際には基本メソッドと比較して追加のプロパティ/メソッドを持たない場合でも、異なる例外を区別する方法です。
したがって、本質的に問題はありませんが、これを慎重に使用することをお勧めします。不適切に設計されたポリモーフィズムで既存のアーキテクチャ上の間違いを隠そうとしているだけではありません。
OrderDateInfo
他に関連するものとSNamedEntity
S