在我们的系统中,我们的域名只是一堆沼泽标准相关的poco,我们使用NHibernate和所有延迟加载等来保持和持久化对象数据
假设我在域中有结构。 (这是我在飞行中创建的一个纯粹的例子)
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public int Id { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Postcode { get; set; }
public Region Region { get; set; }
}
public class Region
{
public int Id { get; set; }
public string Name { get; set; }
public CountryCode CountryCode { get; set; }
}
public class CountryCode
{
public string Name { get; set; }
public string Code { get; set; }
public CostCode CostCode { get; set; }
}
public class CostCode
{
public string Name { get; set; }
public string Description { get; set; }
}
现在说客户想要获取自己的CostCode.Name值,在Customer中有一个方法更好吗
public string GetCountryCostName()
{
return Address.Region.CountryCode.CostCode.Name;
}
或者它会更好,这样做客户和其他对象具有获取信息的功能
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public Address Address { get; set; }
public string GetCountryCostName()
{
return Address.GetCountryCostCodeName();
}
}
public class Address
{
public int Id { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string Postcode { get; set; }
public Region Region { get; set; }
public string GetCountryCostCodeName()
{
return Region.GetCountryCostCodeName();
}
}
public class Region
{
public int Id { get; set; }
public string Name { get; set; }
public CountryCode Country { get; set; }
public string GetCountryCostCodeName()
{
return Country.GetCostCodeName();
}
}
public class CountryCode
{
public string Name { get; set; }
public string Code { get; set; }
public CostCode CostCode { get; set; }
public string GetCostCodeName()
{
return CostCode.Name;
}
}
public class CostCode
{
public string Name { get; set; }
public string Description { get; set; }
}
现在用第一种方式,Nhibernate将创建一个单独的sql来保护它创建的所有代理,但第二种方式如果我在如何延迟加载与NHibernate一起使用它将创建许多较小的sql语句,因为函数被访问。那么哪种方式是OO设计和性能观点的最佳方法呢?
问候
CD
答案 0 :(得分:2)
从SQL和“代码执行方式”的角度来看,这两种方法是相同的。 NHibernate不会为包含Address.Region.CountryCode.CostCode.Name
的方法创建特殊覆盖。这需要在NHibernate上进行一些非常复杂的代码内省。相反,每个many-to-one
属性都使用延迟加载代理对象进行设置。每当您访问代理对象上的非id属性时,NHibernate将确保该对象已从数据库初始化。
从设计的角度来看,你所询问的几乎是Law of Demeter的本质。得墨忒耳法则会说第二种选择,即每个阶级只与其直接邻居交谈,这种选择更好。但是,问题的每一方都有利弊。阅读维基百科文章了解更多详情。
我认为重点是尽量减少受给定更改影响的代码量。如果关于如何访问该值的某些内容必须在该链的中间发生变化,那么您只需要更改一半的类。但是,我们假设客户是唯一真正需要此信息的类。在这种情况下,我认为最好选择第一个选项,忽略德米特定律。是的,您正在向客户提供有关数据结构其余部分的深入信息,但如果该结构发生变化,您只需在Customer中更改一个方法,剩下的就是其他方法。
对于空值,特别是如果数据库允许这些值为null,则不希望将其留给异常处理。对选项#1执行此操作会更好:
public virtual string GetCountryCostName()
{
if (Address == null || Address.Region == null || Address.Region.CountryCode == null || Address.Region.CountryCode.CostCode == null)
return null;
return Address.Region.CountryCode.CostCode.Name;
}
对于选项#2:
public virtual string GetCostCodeName()
{
if (Address == null)
return null;
return Address.GetCostCodeName();
}
// etc...
现在,如果所有这些关系都需要NOT NULL
并由数据库中的外键强制执行,您可以选择跳过if (... == null)
检查,因为在该场景中遇到空值确实会是一个例外情况,这就是例外情况。
P.S。我非常喜欢this answer。