想象一下,我有一个地产网站,可以让你向不同的地产代理商查询有关某一物业的情况。不同的查询方法可能有不同的计费计算与它们相关联,而且并非所有代理都将启用每个计费模型。
public class EmailEnquiryBillingModel : ValueObject
{
public string EmailAddress { get; set; }
public decimal CostPerEnquiry { get; set; }
}
public enum DayOfWeek
{
Monday,
Tuseday,
// etc.
}
public class OpeningHours : ValueObject
{
public DateTime OpeningTime { get; set; }
public DateTime ClosingTime { get; set;}
}
public class PhoneEnquiryBillingModel : ValueObject
{
public PhoneEnquiryBillingModel()
{
OpeningHours = new Dictionary<DayOfWeek, OpeningHours>();
}
public int PhoneNumber { get; set; }
public IDictionary<DayOfWeek, OpeningHours> OpeningHours { get; set; }
}
public class EstateAgent : Entity
{
public string Name { get; set; }
public EmailEnquiryBillingModel EmailEnquiryBillingModel { get; set; }
public PhoneEnquiryBillingModel PhoneEnquiryBillingModel { get; set; }
}NHibernate对组件(值对象)具有语义,如果组件中的每个属性都为空,则组件也将为空。
因此,通过适当的映射,您可以编写if(estateAgent.EmailEnquiryBillingModel != null),而不必检查电子邮件查询计费模型的每个单独属性,或者该模型是否有效:我们要么有模型,要么没有。这是一种简单、优雅的检查特定计费模式是否启用的方法。
当您在组件中有一组时,例如电话查询计费模式和不同的开放时间,问题就会出现。PhoneEnquiryBillingModel和OpeningHours都不是实体。这些都是合法的价值对象:我们不在乎房地产经纪人是周一上午9点开门还是周一上午9点开门,只是周一上午9点开门。
因此,这似乎是在C#中表示此域模型的语义正确的方法。
然而,PhoneEnquiryBillingModel包含一个集合( ProviderOpenHours),而一个集合在NHibernate中不能为空,只能为空,这意味着ProviderOpenHours始终是非空的,即使地产代理没有有意义地启用该查询模型。(有关更多信息,请参见:https://ayende.com/blog/4685/those-are-the-rules-even-when-you-dont-like-them)。
这意味着您不能执行像if(estateAgent.PhoneEnquiryBillingModel != null)这样的简单检查,因为该对象总是非空的。
因此,对于某些计费模型,您可以执行空检查,以查看是否启用了它们,但对于其他计费模型,您必须找到另一种检查方法,这取决于这些计费模型是否包含一个集合。
实际上,您需要了解计费模型的内部结构,才能知道是否可以进行这种比较,这感觉就像您正在打破封装,并根据ORM的规则更改您的域模型。
有什么更好的方法来模拟这个吗?或者让NHibernate在没有电话号码或任何开放时间的情况下,在PhoneEnquiryBillingModel中序列化为null?
发布于 2021-10-13 09:07:53
因此,通过适当的映射,
可以编写if(estateAgent.EmailEnquiryBillingModel != null)
这本身并不是最好的封装。
相反,你选择:
if (estateAgent.DoesAcceptEmailEnquiries())和
if (estateAgent.DoesAcceptPhoneEnquiries())这将提供更好的封装,而不是询问EstageAgent聚合上的属性来假设EstageAgent的功能。如果您决定改变EstateAgent如何在内部存储这些信息的实现呢?你需要改变所有的客户。
EstateAgent对其基础值对象执行单独的属性检查并没有什么特别的坏处。
但是,您可以进一步在PhoneEnquiryBillingModel上实现检查器方法,甚至可能是静态的,以避免在EstateAgent中进行空检查。
PhoneEnquiryBillingModel
public class PhoneEnquiryBillingModel : ValueObject
{
public PhoneEnquiryBillingModel()
{
OpeningHours = new Dictionary<DayOfWeek, OpeningHours>();
}
public int PhoneNumber { get; set; }
public IDictionary<DayOfWeek, OpeningHours> OpeningHours { get; set; }
public static bool DoesAcceptEnquiries(PhoneEnquiryBillingModel phone)
{
if (phone == null) return false;
if (phone.OpeningHours.Count == 0) return false;
return true;
}
}地产代理
public class EstateAgent : Entity
{
public string Name { get; set; }
public EmailEnquiryBillingModel _emailEnquiryBillingModel { get; set; }
public PhoneEnquiryBillingModel _phoneEnquiryBillingModel { get; set; }
public bool DoesAcceptPhoneEnquiries()
{
return PhoneEnquiryBillingModel.DoesAcceptEnquiries(
_phoneEnquiryBillingModel);
}
}https://stackoverflow.com/questions/69547483
复制相似问题