DDD: Thiết kế nhà máy mô hình miền


8

Tôi đang cố gắng để hiểu làm thế nào và ở đâu để thực hiện các nhà máy mô hình miền. Tôi đã bao gồm Companytổng hợp của tôi như là một bản demo về cách tôi đã thực hiện nó.

Tôi đã bao gồm các quyết định thiết kế của tôi vào cuối - tôi sẽ đánh giá cao bất kỳ ý kiến, đề xuất, phê bình về những điểm đó.

Các Companymô hình miền:

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;
    }
}

Nhà CompanyFactorymáy tên miền:

Lớp này được sử dụng để đảm bảo rằng các quy tắc kinh doanh và bất biến không bị vi phạm khi tạo các phiên bản mới của các mô hình miền. Nó sẽ nằm trong lớp miền.

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);
    }
}

Ánh CompanyMapperxạ thực thể:

Lớp này được sử dụng để ánh xạ giữa các mô hình miền phong phú và các thực thể dữ liệu Entity Framework. Nó sẽ nằm trong các lớp cơ sở hạ tầng.

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. Các Companyconstructor được khai báo là internal.
    Lý do: Chỉ có nhà máy nên gọi nhà xây dựng này. internalđảm bảo rằng không có lớp nào khác có thể khởi tạo nó (các lớp được phân tách bằng các dự án VS).

  2. Các CompanyFactory.CreateNew(string name)phương pháp sẽ được sử dụng khi tạo ra một công ty mới trong hệ thống.
    Lý do: Vì nó chưa được duy trì, nên một danh tính duy nhất mới sẽ cần được tạo cho nó (sử dụng IIdentityFactory).

  3. Các CompanyFactory.CreateExisting(int id, string name)phương pháp sẽ được sử dụng bởi các CompanyRepositorymặt hàng khi lấy từ cơ sở dữ liệu.
    Lý do: Mô hình đã có sẵn danh tính, vì vậy điều này sẽ cần được cung cấp cho nhà máy.

  4. Các CompanyMapper.MapFrom(CompanyTable dataEntity)sẽ được sử dụng bởi các CompanyRepositorydữ liệu khi lấy từ sự kiên trì.
    Lý do: Ở đây các thực thể dữ liệu Entity Framework cần được ánh xạ vào các mô hình miền. Các CompanyFactorysẽ được sử dụng để tạo ra các mô hình miền để đảm bảo rằng quy tắc kinh doanh được thỏa mãn.

  5. Các CompanyMapper.MapFrom(Company domainEntity)sẽ được sử dụng bởi các CompanyRepositorymô hình khi thêm hoặc cập nhật để kiên trì.
    Lý do: Các mô hình miền cần được ánh xạ thẳng vào các thuộc tính thực thể dữ liệu để Entity Framework có thể nhận ra những thay đổi cần thực hiện trong cơ sở dữ liệu.

Cảm ơn

Câu trả lời:


2

Có một điều tôi không thích về thiết kế của bạn. Và đó là thực tế bạn sẽ có thêm 3 lớp cho mỗi gốc tổng hợp (Factory, Mapper, Rep Storage) với mã bán trùng lặp ở dạng đọc và đặt thuộc tính ở mọi nơi. Điều này sẽ có vấn đề khi bạn thêm và xóa các thuộc tính, vì việc quên thay đổi một phương thức có thể gây ra lỗi. Và thực thể miền càng phức tạp thì mã trùng lặp này càng nhiều. Tôi không muốn thấy CompanyFactory.CreateExistingkhi công ty có 10 thuộc tính và 2 thực thể trong tổng hợp.

Điều thứ hai tôi có thể phàn nàn là IdentityFactory. Trong DDD, danh tính phải liên quan đến tên miền, trong trường hợp đó bạn đặt nó thành một số giá trị được tính toán. Hoặc nó là minh bạch, trong trường hợp đó bạn có thể có DB chăm sóc nó. Thêm một số loại nhà máy để nhận dạng là IMO áp đảo.

Tôi cũng không thích lập bản đồ. Mặc dù tôi đồng ý rằng có thể không thể sử dụng trực tiếp EntityFramework, nhưng ít nhất bạn có thể thử. Gần đây, EF đang trở nên tốt hơn với POCO và bạn có thể ngạc nhiên về mức độ mạnh mẽ của nó. Nhưng nó vẫn không phải là NHibernate. Nếu bạn thực sự muốn tạo các mô hình riêng biệt, hãy thử nghĩ về việc sử dụng một số thư viện tự động ánh xạ.

Thật tuyệt khi bạn đang demo thiết kế trên một lớp đơn giản, nhưng hãy thử demo hoặc ít nhất là tưởng tượng cách thiết kế sẽ hoạt động với hàng tá tập hợp có nhiều thuộc tính và thực thể. Ngoài ra, viết một mã sẽ sử dụng thiết kế này. Bạn có thể nhận ra rằng mặc dù thiết kế có thể trông đẹp từ bên trong, nhưng nó lại cồng kềnh khi sử dụng từ bên ngoài. Ngoài ra, không ai ở đây sẽ cho bạn biết nếu thiết kế phù hợp với nhóm của bạn và tên miền của bạn.


Cảm ơn câu trả lời của bạn. Chúng tôi đã loại trừ EF POCO dưới dạng mô hình miền vì nó đưa ra các ràng buộc về cách chúng tôi thiết kế các mô hình của mình. Chúng tôi có thể sử dụng thư viện tự động hóa, nhưng điều đó chỉ có thể áp dụng khi ánh xạ tới các thực thể dữ liệu EF chứ không phải cho các mô hình miền. Lý do là: Ánh xạ tới mô hình miền nên sử dụng nhà máy, không nên sao? Nếu không, bạn có nguy cơ các mô hình miền không hợp lệ trôi nổi trên hệ thống của bạn. Tôi đồng ý rằng có rất nhiều "mã đường ống". Việc thêm các tập hợp mới, hoặc thậm chí thêm các thuộc tính cho các thực thể hiện có, đòi hỏi khá nhiều mã giàn giáo.
Dave New

1
+1. Tôi đặc biệt đồng ý về "Mapper" - theo hiểu biết của tôi, một ORM tốt sẽ làm cho sự khác biệt giữa "các lớp miền" và "các lớp thực thể" không cần thiết. Bạn có một đề nghị cho một sự thay thế cho các CompanyFramework.CreateExistingcông trình? Một điều tôi không thấy là một điểm yếu là IIdentityFactory. Nếu ID được tạo từ cơ sở dữ liệu, bạn nên có một cơ chế để giả định điều này, để cho phép thử nghiệm đơn vị với cơ sở dữ liệu.
Doc Brown

DocBrown là tại chỗ về IIdentityFactory. Trong DDD, các thực thể cần phải có danh tính từ thời điểm tạo. Thật không may, chúng tôi không có khả năng sử dụng Guidcác loại. Chúng ta phải tạo ra int Idstừ cơ sở dữ liệu trước khi sự kiên trì xảy ra. Một lý do khác cho một nhà máy.
Dave New

1
@DocBrown Thay thế cho CompanyFramework.CreateEx hiện tại là một ORM tốt. Vấn đề với ID là trừ khi ID là mối quan tâm của miền, trong trường hợp bạn tạo ra nó theo một cách nào đó, sẽ không có ID. ID dành cho DB để giữ thông tin về các mối quan hệ, nhưng trong DDD, cần được xử lý bởi các tham chiếu đối tượng. Trong trường hợp đó, không cần phải tạo nó trước khi nó được lưu trong DB.
Euphoric
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.