0

我有以下问题一直困扰着我很长一段时间。我想为以下域实体“联系人”建模:

public class Contact:IEntity<Contact>
{
    private readonly ContactId _Id;
    public ContactId Id
    {
        get { return this._Id; }
    }


    private CoreAddress _CoreAddress;
    public CoreAddress CoreAddress
    {
        get { return this._CoreAddress; }
        set
        {
            if (value == null)
                throw new ArgumentNullException("CoreAddress");
            this._CoreAddress = value;
        }
    }


    private ExtendedAddress _ExtendedAddress;
    public ExtendedAddress ExtendedAddress
    {
        get { return this._ExtendedAddress; }
        set
        {
            if (value == null)
                throw new ArgumentNullException("ExtendedAddress");
            this._ExtendedAddress = value;
        }
    }

    private readonly IList<ContactExchangeSubscription> _Subscriptions
        = new List<ContactExchangeSubscription>();

    public IEnumerable<ContactExchangeSubscription> Subscriptions
    {
        get { return this._Subscriptions; }
    }

    public Contact(ContactId Id, CoreAddress CoreAddress, ExtendedAddress ExtendedAddress)
    {
        Validations.Validate.NotNull(Id);
        this._Id = Id;
        this._CoreAddress = CoreAddress;
        this._ExtendedAddress = ExtendedAddress;
    }
  }

如您所见,它有一系列订阅。订阅的建模如下:

 public class ContactExchangeSubscription
{
    private ContactId _AssignedContact;
    public ContactId AssignedContact
    {
        get { return this._AssignedContact; }
        set
        {
            if (value == null)
                throw new ArgumentNullException("AssignedContact");
            this._AssignedContact = value;
        }
    }

    private User _User;
    public User User
    {
        get { return this._User; }
        set
        {
            Validations.Validate.NotNull(value, "User");
            this._User = value;
        }
    }


    private ExchangeEntryId _EntryId;
    public ExchangeEntryId EntryId
    {
        get { return this._EntryId; }
        set
        {
            if (value == null)
                throw new ArgumentNullException("EntryId");
            this._EntryId = value;
        }
    }


    public ContactExchangeSubscription(ContactId AssignedContact, User User, ExchangeEntryId EntryId)
    {
        this._AssignedContact = AssignedContact;
        this._User = User;
        this._EntryId = EntryId;
    }



}

现在我一直在想,我不应该在我的领域中为存储技术 (Exchange) 建模,毕竟,我们可能希望将我们的应用程序切换到其他订阅提供商。属性“EntryId”特定于 Exchange。不过,订阅总是需要一个 User 和一个 ContactId。有没有更好的方法来为订阅建模?如果需要,我应该为 Subscription 类型使用工厂还是抽象工厂来涵盖其他类型的订阅?

编辑:所以让我们在环中折腾一个抽象工厂并引入一些接口:

public interface IContactSubscriptionFactory
{
    IContactSubscription Create();
}

public interface IContactSubscription
{
    ContactId AssignedContact { get;}
    User User { get; }
}

ContactExchangeSubscription 的具体工厂如何编码?请记住,此类型将需要 EntryID 字段,因此它必须获取一个额外的 ctr 参数。一般如何处理工厂中不同子类型的不同构造函数参数?

4

2 回答 2

1

我认为答案就在你眼前,因为你需要努力在未来interface更容易引入新的订阅提供商(如果这是正确的术语)。我认为这更像是 DDD 的一个 OO 设计问题。

public interface ISubscriptionProvider
{
    ContactId AssignedContact { get; }
    User User { get; }
}

你合同中的代码变成了

private readonly IList<ISubscriptionProvider> _subscriptions
    = new List<ISubscriptionProvider>();

public IEnumerable<ISubscriptionProvider> Subscriptions
{
    get { return _subscriptions; }
}

关于使用工厂;工厂的目的是在需要创建策略时构造域对象。例如,当您重新水化聚合时,可以在您的存储库中使用 SubscriptionProviderFactory,并根据传入的数据决定返回 ContactExchangeSubscription(作为 ISubscriptionProvider)或其他内容。

最后一点,但也许这只是因为您展示示例的方式。但我想说你没有真正遵循 DDD,缺乏行为以及你所有的属性都有公共 getter 和 setter,这表明你掉进了构建Aemic Domain Model的陷阱。

于 2012-07-11T06:13:01.400 回答
0

经过一番研究,我想出了这个。先上代码,解释如下:

public interface IContactFactory<TSubscription> where TSubscription : IContactSubscription
{
    Contact Create(ContactId Id, CoreAddress CoreAddress, ExtendedAddress ExtendedAddress, TSubscription Subscription);
}

public class ContactFromExchangeFactory : IContactFactory<ContactExchangeSubscription>
{
    public Contact Create(ContactId Id, CoreAddress CoreAddress, ExtendedAddress ExtendedAddress, ContactExchangeSubscription ExchangeSubscription)
    {
        Contact c = new Contact(Id, CoreAddress, ExtendedAddress);
        c.AddSubscription(ExchangeSubscription);
        return c;
    }
}

我意识到我不需要联系人订阅的工厂,而是联系人本身。

一路上我学到了一些关于工厂的事情:

  • 它们仅在创建(真正)新实体时使用,而不是在从 SQL DB 重建它们时使用
  • 他们生活在领域层(见上文!)
  • 工厂更适合行为不同的相似对象而不是数据

我欢迎评论和更好的答案。

于 2012-07-12T18:57:51.290 回答