データ型のインターフェースの使用はアンチパターンですか?


9

モデルに(EFを使用して)さまざまなエンティティがあるとします(ユーザー、製品、請求書、注文など)。

エンティティが事前に決定されたセットに属しているアプリケーションでエンティティオブジェクトの要約を印刷できるユーザーコントロールを作成しています。この場合、ユーザーと製品の要約を要約できると言います。

要約にはすべてIDと説明しか含まれないため、このための簡単なインターフェースを作成します。

 public interface ISummarizableEntity {     
       public string ID { get; }    
       public string Description { get; } 
 }

次に、問題のエンティティについて、このインターフェイスを実装する部分クラスを作成します。

public partial class User : ISummarizableEntity
{
    public string ID
    {
        get{ return UserID.ToString(); }
    }

    public string Description 
    {
        get{ return String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age); }
    }
}

public partial class Product: ISummarizableEntity
{
    public string ID
    {
        get{ return ProductID.ToString(); }
    }

    public string Description 
    {
        get{ return String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department); }
    }
}

このようにして、ユーザーコントロール/部分ビューはISummarizableEntityの任意のコレクションにバインドでき、ソースにまったく関心を持つ必要がありません。インターフェイスをデータ型として使用するべきではないと言われましたが、それ以上の情報は得られませんでした。私の知る限りでは、インターフェイスは通常動作を説明しますが、プロパティはゲッター/セッターの構文上の砂糖であるため、プロパティを使用するだけではアンチパターンではありません。

具体的なデータ型を作成し、エンティティからそれにマッピングすることはできますが、メリットがわかりません。エンティティオブジェクトを抽象クラスから継承してプロパティを定義することもできますが、多重継承ができないため、エンティティをロックしてこれ以上使用できません。また、必要に応じて、オブジェクトをISummarizableEntityにすることもできます(明らかに、インターフェイスの名前を変更します)

私が心の中で使用しているソリューションは、保守、拡張、テストが可能で、かなり堅牢です。ここにアンチパターンが見えますか?


以下のようなものを持つ以上、あなたがこれを好む何らかの理由があるEntitySummaryと、UserそしてProductそれぞれのようなメソッドを持つにはpublic EntitySummary GetSummary()
Ben Aaronson、2015年

@ベン、あなたは有効なオプションを提案します。しかし、それでも、オブジェクトにGetSummary()メソッドがあることを期待できることを呼び出し元に知らせるインターフェイスの定義が必要になります。これは基本的に同じ設計であり、実装にモジュール性のレベルが追加されています。要約がそのソースから独立して(ただし短時間でも)単独で生きる必要がある場合は、良い考えかもしれません。
ケントA.

@KentAnderson同意する。これらのクラスの全体的なインターフェイスと集計の使用方法によっては、実際には良いアイデアかもしれませんし、そうでないかもしれません。
Ben Aaronson、2015年

回答:


17

インターフェイスは動作を記述していません。まったく逆の場合もあります。

インターフェイスは、「ISummarizableEntityを受け入れるメソッドにこのオブジェクトを提供する場合、このオブジェクトはそれ自体を要約できるエンティティである必要がある」などの規約を記述します-あなたの場合、それは、文字列IDと文字列Description。

これはインターフェースの完璧な使い方です。ここにはアンチパターンはありません。


2
「インターフェースは動作を説明するものではありません。」「自分自身を要約する」ことはどのように行動ではないのですか?
ドヴァル2015年

2
@ThomasStringer、継承、オブジェクト指向の純粋主義者の観点から、共通の祖先を意味します(たとえば、正方形は両方とも形状です)。OPの例では、ユーザーと製品は合理的な共通の祖先を共有していません。この場合の継承は、明らかにアンチパターンです。
ケントA.

2
@Doval:インターフェースの名前が期待される動作を説明していると思います。しかし、そうである必要はありません。インターフェイスはIHasIdAndDescriptionという名前にすることもでき、答えは同じになります。インターフェイス自体は動作を説明するのではなく、期待を説明します。
pdr 2015年

2
@pdrヘッドフォンジャックから20Vを送ると、悪いことが起こります。形状は十分ではありません。そのプラグを介してどのような信号が発生するかについて、非常に現実的で非常に重要な期待があります。これがまさに、インターフェースに動作仕様が関連付けられていないふりをするのが間違っている理由です。Listリストのように動作しないa で何ができますか?
ドヴァル2015年

3
適切なインターフェースを備えた電気プラグがコンセントに収まる場合がありますが、それが電気を伝導することを意味するわけではありません(望ましい動作)。
JeffO 2015年

5

複数の異なるタイプのオブジェクトに必要となる特定のタイプの動作を定義しているため、この設計により適したパスを選択しました。この場合の継承は、実際には存在しないクラス間の共通の関係を意味します。この場合、継承よりも構成可能性が優先されます。


3
インターフェイスは継承とは何の関係もありません。
DougM 2015年

1
@DougM、たぶん私はそれをうまく言っていなかったかもしれませんが、私たちは同意することはかなり確信しています。
ケントA.

1

プロパティのみを運ぶインタフェースは、必要があるので、避けること。

  • それは意図を難読化します:あなたはデータコンテナだけを必要とします
  • それは継承を奨励します:誰かが将来的に懸念を混合する可能性
  • シリアル化を妨げます

ここでは、2つの懸念が混在しています。

  • データとしての要約
  • 契約としての要約

概要は、IDと説明の2つの文字列で構成されます。これは単純なデータです:

public class Summary {
    private readonly string id;
    private readonly string description;
    public Summary(string id, string description) {
        this.id = id;
        this.description = description;
    }
    public string Id { get { return id; } }
    public string Description { get { return description; } }
}

これで、契約を定義したいサマリーが定義されました。

public interface ISummarizableEntity {
    public Summary GenerateSummary();
}

ゲッターでインテリジェンスを使用することはアンチパターンであり、避けるべきであることに注意してください。代わりに関数内に配置する必要があります。実装は次のようになります。

public partial class User : ISummarizableEntity {
    public Summary GenerateSummary() {
        var id = UserID.ToString();
        var description = String.Format("{0} {1} is from {2} and is {3} years old", FirstName, LastName, Country, Age);
        return new Summary(id,description);
    }
}

public partial class Product : ISummarizableEntity {
    public Summary GenerateSummary() {
        var id = ProductID.ToString();
        var description = String.Format("{0} weighs {1}{2} and belongs in the {3} department", ProductName, WeightValue, WeightUnit, Department);
        return new Summary(id,description);
    }
}

「プロパティのみを保持するインターフェースは避けるべきです」私は同意しません。なぜそう思うのか、理由を説明してください。
陶酔の

私はいくつかの詳細を追加しました
ヴァンナ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.