DDD:ドメインモデルファクトリデザイン


8

ドメインモデルファクトリを実装する方法と場所を理解しようとしています。Company集計を、それをどのように行ったかのデモとして含めました。

私は最後に私の設計決定を含めました-それらの点に関するコメント、提案、批評をいただければ幸いです。

Companyドメインモデル:

public class Company : DomainEntity, IAggregateRoot
{
    private string name;
    public string Name
    {
        get
        {
            return name;
        }
        private set
        {
            if (String.IsNullOrWhiteSpace(value))
            {
                throw new ArgumentOutOfRangeException("Company name cannot be an empty value");
            }

            name = value;
        }
    }

    internal Company(int id, string name)
    {
        Name = name;
    }
}

CompanyFactoryドメイン工場:

このクラスは、ドメインモデルの新しいインスタンスを作成するときに、ビジネスルールと不変条件に違反しないようにするために使用されます。ドメイン層に存在します。

public class CompanyFactory
{
    protected IIdentityFactory<int> IdentityFactory { get; set; }

    public CompanyFactory(IIdentityFactory<int> identityFactory)
    {
        IdentityFactory = identityFactory;
    }

    public Company CreateNew(string name)
    {
        var id = IdentityFactory.GenerateIdentity();

        return new Company(id, name);
    }

    public Company CreateExisting(int id, string name)
    {
        return new Company(id, name);
    }
}

CompanyMapperエンティティマッパー:

このクラスは、リッチドメインモデルとEntity Frameworkデータエンティティ間のマッピングに使用されます。インフラストラクチャ層に存在します。

public class CompanyMapper : IEntityMapper<Company, CompanyTable>
{
    private CompanyFactory factory;

    public CompanyMapper(CompanyFactory companyFactory)
    {
        factory = companyFactory;
    }

    public Company MapFrom(CompanyTable dataEntity)
    {
        return DomainEntityFactory.CreateExisting(dataEntity.Id, dataEntity.Name);
    }

    public CompanyTable MapFrom(Company domainEntity)
    {
        return new CompanyTable()
        {
            Id = domainEntity.Id,
            Name = domainEntity.Name
        };
    }
}
  1. Companyコンストラクタは、次のように宣言されていますinternal
    理由:ファクトリーのみがこのコンストラクターを呼び出す必要があります。 internal他のレイヤーがインスタンス化できないようにします(レイヤーはVSプロジェクトによって分離されます)。

  2. このCompanyFactory.CreateNew(string name)方法は、システムで新しい会社を作成するときに使用されます。
    理由:まだ永続化されていないため、新しい一意のIDを生成する必要があります(を使用IIdentityFactory)。

  3. このCompanyFactory.CreateExisting(int id, string name)メソッドはCompanyRepository、データベースからアイテムを取得するときにによって使用されます。
    理由:モデルにはすでにIDがあるため、これをファクトリーに提供する必要があります。

  4. CompanyMapper.MapFrom(CompanyTable dataEntity)使用されるCompanyRepository永続からデータを取り出します。
    理由:ここでは、Entity Frameworkデータエンティティをドメインモデルにマップする必要があります。CompanyFactoryビジネスルールが満たされていることを保証するために、ドメインモデルを作成するために使用されます。

  5. CompanyMapper.MapFrom(Company domainEntity)で使用されるCompanyRepository持続性への追加や更新モデル。
    理由: Entity Frameworkがデータベースで行う変更を認識できるように、ドメインモデルをデータエンティティのプロパティに直接マッピングする必要があります。

ありがとう

回答:


2

あなたのデザインについて気に入らないことが1つあります。そして、実際には、各ルート(Factory、Mapper、Repository)ごとに3つの追加クラスがあり、どこでもプロパティの読み取りと設定を行う形式の半重複コードがあります。単一のメソッドを変更し忘れるとエラーが発生する可能性があるため、これはプロパティを追加および削除するときに問題になります。また、ドメインエンティティが複雑であるほど、この重複コードは多くなります。CompanyFactory.CreateExisting会社が合計で10のプロパティと2のエンティティを持っているときを見たくありません。

私が不平を言うかもしれない2番目のことはIdentityFactoryです。DDDでは、IDはドメインに関連している必要があります。その場合は、何らかの計算値に設定します。または、透過的です。その場合、DBに処理させることができます。アイデンティティのためのある種のファクトリを追加することは、IMOオーバーエンジニアリングです。

私もマッピングが好きではありません。EntityFrameworkを直接使用することは不可能かもしれないと私は同意しますが、少なくとも試すことができます。EFは最近POCOでより良くなっており、それがどれほど強力であるかに驚くかもしれません。しかし、それはまだNHibernateではありません。本当に別のモデルを作成したい場合は、自動マッピングライブラリの使用を検討してください。

1つの単純なクラスでデザインをデモしているのは良いことですが、デモや少なくとも、多数のプロパティとエンティティを持つ多数の集計でデザインがどのように機能するかを想像してみてください。また、このデザインを使用するコードを記述します。デザインは内側から見た目は良いかもしれませんが、外側から使うのは面倒です。また、設計がチームやドメインに適しているかどうかは、ここでは誰にも説明されません。


ご回答有難うございます。EF POCOは、モデルの設計方法に制約を導入するため、ドメインモデルとして除外しました。自動マッピングライブラリを使用することもできますが、これはドメインモデルではなくEFデータエンティティにマッピングする場合にのみ適用されます。理由:ドメインモデルへのマッピングにはファクトリを使用する必要がありますね。そうしないと、無効なドメインモデルがシステムの周りに浮かぶ可能性があります。「パイピングコード」がたくさんあることに同意します。新しい集計を追加したり、既存のエンティティにプロパティを追加したりするには、かなりの足場コードが必要です。
デイブニュー

1
+1。特に「マッパー」について同意します-私の理解では、優れたORMは「ドメインクラス」と「エンティティクラス」の区別を不要にする必要があります。CompanyFramework.CreateExisting構成の代替案を提案していますか?弱点とは思えないのは、IIdentityFactoryです。IDがデータベースから生成される場合、データベースでの単体テストを可能にするために、これを模擬するメカニズムが必要です。
Doc Brown、

DocBrownはに関してスポットを当てていIIdentityFactoryます。DDDでは、エンティティは作成の瞬間からアイデンティティを持つ必要があります。残念ながら、Guid型を使用できるという贅沢はありません。int Ids永続化が発生する前に、データベースから生成する必要があります。工場のもう一つの理由。
Dave New 14

1
@DocBrown CompanyFramework.CreateExistingの代替は、優れたORMです。IDに関することは、IDがドメインに関係しない限り、何らかの方法で生成した場合、IDが存在しないことです。IDは、DBが関係に関する情報を保持するためのものですが、DDDでは、オブジェクト参照によって処理する必要があります。その場合、DBに保存する前に生成する必要はありません。
陶酔
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.