有时您无法避免紧密耦合,就像在您的示例中一样。但是,这并不意味着您也需要接受它。相反,通过封装混乱并将其从您的日常生活中分离出来来隔离它。
例如,如果我们想要当前的 Forms Authentication 用户,我们别无选择,只能访问HttpContext.Current.Request.User.Identity.Name
. 但是,我们确实可以选择在哪里拨打电话。
HttpContext.Current
是解决问题的方法。当我们直接从我们使用结果的地方调用它时,我们在同一个地方声明了问题和解决方案:“我需要当前用户名,它被坚定地声明为来自当前 HTTP 上下文。” 这混淆了两者的定义,并且不允许对同一问题有不同的解决方案。
我们缺少的是对我们正在解决的问题的清晰表述。对于此示例,它将类似于:
确定发出当前请求的用户
HttpContext.Current
我们使用,甚至是用户名这一事实都不是核心问题定义的一部分;它是一个实现细节,只会使需要当前用户的代码复杂化。
我们可以通过一个接口来表示检索当前用户的意图,没有实现细节:
public interface IUserContext
{
User GetUser();
}
我们直接调用的任何类HttpContext.Current
现在都可以使用这个由容器注入的接口来维护 DI 的优点。IUserContext
对于一个类来说,在其构造函数中接受一个比具有从其公共 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);
}
}