一位开发人员和我正在谈论(轻描淡写)对象的属性的惰性加载。控制反转,依赖注入瓦特/ SRP和延迟加载
- 他说,要使用静态IoC查找调用来解析对象的对象并延迟加载对象。
- 我说违反SRP,并使用拥有的服务来解决该对象。
那么,如何处理IoC和SRP之后的Lazy-Loading?
你不能单元测试那个懒加载的属性。他斥责那个人说:“你已经为UserStatsService进行了单元测试 - 这是你的代码覆盖范围。”一个有效的点,但该属性仍然未经测试,但“完整”的覆盖。
设置/码型:
- 项目采用严格的依赖注入规则(在所有服务中,库的构建函数注入,等等)。
- 项目通过Castle的方式使用IoC(但可以是Unity等任何项目)。
一个例子如下。
public class User
{
public Guid UserId { get; set; }
private UserStats _userStats;
// lazy-loading of an object on an object
public UserStats UserStats
{
get
{
if (_userStats == null)
{
// ComponentsLookup is just a wrapper around IoC
// Castle/Unity/etc.
_userStats =
ComponentsLookup
.Fetch<UserStatsService>()
.GetByUserId(this.UserId);
}
return _userStats;
}
}
}
以上显示了一个延迟加载对象的示例。我说不要使用它,并且在需要该对象的任何地方从UI层访问UserStatsService。
编辑:下面的一个答案提醒我关于延迟加载的NHibernate技巧,这是虚拟化您的属性,允许NHibernate创建延迟加载本身的过载。光滑,是的,但我们没有使用NHibernate。
没有人真正解决延迟加载的问题。一些好的文章,做题亲近:
- Using Dependency Injection frameworks for classes with many dependencies
- http://blog.vuscode.com/malovicn/archive/2009/10/16/inversion-of-control-single-responsibility-principle-and-nikola-s-laws-of-dependency-injection.aspx
我看到延迟加载的好处。不要误解我的意思,我只是懒惰地加载了我的复杂类型和它们的子类型,直到我转向忍者的D.I.方式。好处是在用户的统计信息显示在用户界面层,例如,在100行的列表中。但是对于DI,现在您必须引用几行代码才能获得该用户的统计信息(不违反SRP并且不违反德米特定律),并且必须经过这么长的查找路径100多次。
是的,加入缓存并确保UserStatsService被编码为Singleton模式,大大降低了性能成本。
但我想知道是否有其他人有[固执]的开发人员,不会屈服于IoC和D.I.完全规则,并具有有效的性能/编码点来证明解决方法的正确性。
+1我完全同意这个问题应该在实体之外。有了NHibernate(我知道它是如何重载延迟加载属性的,是的),这很容易。但是,我们不使用NHibernate。另外,在你描述的罕见用例(没有NHibernate)的情况下,这很容易使用大量的内存 - 将子属性加载到回购级别。因此,延迟加载的概念仅适用于需要的情况下的高性能。我会继续研究其他模式。 – eduncan911 2010-01-12 19:59:34
在IList <>下执行延迟加载与NHibernate无关;这只是一个简单的例子。它对静态调用的主要好处是上下文敏感。当你将一个静态调用放入一个类中时,你会自动将其上下文整个AppDomain,要求每个实例的工作方式完全相同。假设您有一个实体的列表页面和导出。您可能会延迟加载列表页面,但会导致出口负载过重(因为您知道您将处理所有内容)。这种上下文行为(以及批处理大小等)基本上被静态调用所排除。 – 2010-01-13 00:24:19