使用工厂模式对类似订阅进行建模

时间:2012-07-10 20:43:00

标签: domain-driven-design factory-pattern

我有以下问题一直在唠叨我一段时间。 我想建模以下域实体“联系人”:

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。 是否有更好的方式来建模订阅?如果需要,我应该使用工厂或抽象工厂作为订阅类型来涵盖其他类型的订阅吗?

编辑:那么让我们在环中抛出一个抽象工厂并介绍一些接口:

public interface IContactSubscriptionFactory
{
    IContactSubscription Create();
}

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

如何编写ContactExchangeSubscription的具体工厂?请记住,此类型需要EntryID字段,因此必须获取其他ctr参数。如何在工厂中处理不同子类型的不同构造函数参数?

2 个答案:

答案 0 :(得分: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,缺乏行为以及你所有的公共吸气者和制定者,建议你陷入建立Aemic Domain Model的陷阱。

答案 1 :(得分: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;
    }
}

我意识到我不需要工厂用于Contactsubscription,而是用于联系本身。

我沿途学到了一些关于工厂的事情:

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

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