经过多次踢打和尖叫之后,我开始接受 DI,尽管随着依赖性的增长,SL 看起来更加清晰。
但是,IMO 在 DI 方面仍然存在重大障碍:
当您无法控制对象的实例化时,DI 是不可能的。在 ASP.NET 世界中,示例包括:HttpModule、HttpHandler、Page 等。
在上面的场景中,我们将求助于静态服务位置来解决依赖关系,通常是通过 HttpContext.Current
,它总是从当前线程推断范围。因此,如果我们要在这里使用静态 SL,那么为什么不在其他地方也使用它呢?
答案是否简单到:咬紧牙关,在必要时使用 SL(如上),但尽量偏爱 DI?如果是这样:只使用一次静态 SL 不会破坏整个应用程序的一致性吗?从本质上消除 DI 在其他地方的辛勤工作?
最佳答案
有时您无法避免紧耦合,就像在您的示例中一样。但是,这并不意味着您也需要接受它。相反,通过封装困惑并将其从您的日常生活中分离出来来隔离它。
例如,如果我们想要当前的 Forms 身份验证用户,我们别无选择,只能访问 HttpContext.Current.Request.User.Identity.Name
。但是,我们确实可以选择在哪里进行调用。
HttpContext.Current
是一个问题的解决方案。当我们直接从我们使用结果的地方调用它时,我们是在同一个地方声明问题和解决方案:“我需要当前用户名,它被坚定地声明为来自当前 HTTP 上下文。”这混淆了两者的定义,并且不允许对同一问题有不同的解决方案。
我们缺少的是对我们正在解决的问题的清晰表述。对于这个例子,它会是这样的:
Determine the user which made the current request
我们正在使用 HttpContext.Current
甚至用户名这一事实并不是核心问题定义的一部分;它是一个实现细节,只会使需要当前用户的代码复杂化。
我们可以通过接口(interface)表示检索当前用户的意图,没有实现细节:
public interface IUserContext
{
User GetUser();
}
我们直接调用 HttpContext.Current
的任何类现在都可以改用这个由容器注入(inject)的接口(interface),以保持 DI 的良好状态。对于一个类来说,在其构造函数中接受 IUserContext
比具有无法从其公共(public) API 中看到的依赖项更能揭示意图。
实现将静态调用隐藏在一个地方,它不会再伤害我们的对象:
public class FormsUserContext : IUserContext
{
private readonly IUserRepository _userRepository;
public FormsUserContext(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public User GetUser()
{
return _userRepository.GetByUserName(HttpContext.Current.Request.User.Identity.Name);
}
}
关于c# - 如果无法进行依赖注入(inject)怎么办?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5060353/