我和一位开发人员正在就对象属性的延迟加载进行交谈(轻描淡写)。
- 他说使用静态 IoC 查找调用来解析和延迟加载对象的对象。
- 我说这违反了 SRP,并使用拥有的服务来解决该对象。
那么,您将如何处理 IoC 和 SRP 之后的延迟加载?
您不能对延迟加载的属性进行单元测试。他反驳了这一说法,“你已经对 UserStatsService 进行了单元测试——你的代码覆盖了。” 一个有效的观点,但该属性仍未经过“完整”覆盖的测试。
设置/代码模式:
- 项目正在使用严格的依赖注入规则(注入到所有服务、存储库等的 ctors 中)。
- 项目通过 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 创建延迟加载本身的过载。Slick,是的,但我们没有使用 NHibernate。
没有人真正解决延迟加载的问题。一些好的文章和 SO 问题接近了:
- 对具有许多依赖项的类使用依赖注入框架
- http://blog.vuscode.com/malovicn/archive/2009/10/16/inversion-of-control-single-responsibility-principle-and-nikola-s-laws-of-dependency-injection.aspx
我确实看到了延迟加载的好处。不要误会,我所做的只是延迟加载我的复杂类型及其子类型,直到我切换到忍者的 DI 方式。好处在于 UI 层,其中显示了用户的统计信息,例如,在 100 行的列表中。但是对于 DI,现在您必须引用几行代码来获取该用户统计信息(不违反 SRP 并且不违反 Demeter 定律),并且它必须走这条长长的查找路径 100 多次。
是的,添加缓存并确保将 UserStatsService 编码为用作单例模式会大大降低性能成本。
但我想知道是否还有其他人有一个 [固执的] 开发人员,他们不会完全遵守 IoC 和 DI 规则,并且有有效的性能/编码点来证明变通方法的合理性。