我有以下问题一直在唠叨我一段时间。 我想建模以下域实体“联系人”:
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参数。如何在工厂中处理不同子类型的不同构造函数参数?
答案 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,而是用于联系本身。
我沿途学到了一些关于工厂的事情:
我欢迎评论和更好的答案。