2010-01-12 32 views
2

一位开发人员和我正在谈论(轻描淡写)对象的属性的惰性加载。控制反转,依赖注入瓦特/ 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。

没有人真正解决延迟加载的问题。一些好的文章,做题亲近:

我看到延迟加载的好处。不要误解我的意思,我只是懒惰地加载了我的复杂类型和它们的子类型,直到我转向忍者的D.I.方式。好处是在用户的统计信息显示在用户界面层,例如,在100行的列表中。但是对于DI,现在您必须引用几行代码才能获得该用户的统计信息(不违反SRP并且不违反德米特定律),并且必须经过这么长的查找路径100多次。

是的,加入缓存并确保UserStatsService被编码为Singleton模式,大大降低了性能成本。

但我想知道是否有其他人有[固执]的开发人员,不会屈服于IoC和D.I.完全规则,并具有有效的性能/编码点来证明解决方法的正确性。

回答

4

实体本身不应该承担延迟加载的责任。这是一项基础设施问题,其解决方案将存在于别处。

假设实体在两个不同的上下文中使用。在第一种情况下,它的孩子被大量使用并且急切地被装载。在第二种情况下,它们很少被使用,并且被延迟加载。这也是该实体的担忧吗?配置会是什么样子?

NHibernate通过代理实体类型来回答这些问题。 IList<Entity>类型的属性由基础结构设置为知道延迟加载的实现。该实体仍然幸福地不知道。父引用(如你的问题)也被处理,只需要一个简单的属性。

既然担心是在实体之外,那么基础架构(ORM)负责确定上下文和配置(如预先加载/延迟加载)。

+0

+1我完全同意这个问题应该在实体之外。有了NHibernate(我知道它是如何重载延迟加载属性的,是的),这很容易。但是,我们不使用NHibernate。另外,在你描述的罕见用例(没有NHibernate)的情况下,这很容易使用大量的内存 - 将子属性加载到回购级别。因此,延迟加载的概念仅适用于需要的情况下的高性能。我会继续研究其他模式。 – eduncan911 2010-01-12 19:59:34

+0

在IList <>下执行延迟加载与NHibernate无关;这只是一个简单的例子。它对静态调用的主要好处是上下文敏感。当你将一个静态调用放入一个类中时,你会自动将其上下文整个AppDomain,要求每个实例的工作方式完全相同。假设您有一个实体的列表页面和导出。您可能会延迟加载列表页面,但会导致出口负载过重(因为您知道您将处理所有内容)。这种上下文行为(以及批处理大小等)基本上被静态调用所排除。 – 2010-01-13 00:24:19