【问题标题】:What are hidden dependencies?什么是隐藏依赖?
【发布时间】:2018-03-18 21:05:40
【问题描述】:
【问题讨论】:
标签:
c#
dependency-injection
dependencies
【解决方案1】:
透明(具体)依赖:透明依赖是通过公共构造函数设置的依赖。
不透明(隐藏)依赖:不透明依赖是不通过公共构造函数设置的依赖,因此不容易看到依赖
这是一个例子:
// Transparent Dependency
public class StudentService
{
private IStudentRepository _studentRepository;
public StudentService(IStudentRepository studentRepository)
{
_studentRepository = studentRepository;
}
public List<Student> GetStudents()
{
return _studentRepository.GetAllStudents();
}
}
// Opaque Dependency
public class StudentService
{
public List<Student> GetStudents()
{
var _studentRepository = new StudentRepository("my-db-name");
return _studentRepository.GetAllStudents();
}
}
Opaque Dependecies 被认为是一种反模式,this article 强调了 Opaque IoC 的问题:
为实现不透明 IoC 的组件编写测试要困难得多
透明 IoC 帮助身份类别做得“太多”
Mark Seemann describes优雅的第二点:
构造函数注入的一大好处是它
明显违反单一责任原则
很明显。
与此密切相关的是Nikola's 2nd law of IoC:
任何具有超过 3 个依赖项的类都应该受到 SRP 的质疑
违规
【解决方案2】:
下面是隐藏依赖的例子:
class Foo
{
void doSomething() //a visible method signature
{
//the body of this method is an implementation detail
//and is thus hidden
new Bar().doSomething();
}
}
在上面的例子中,Bar 是Foo 的依赖,因为Foo 依赖于Bar 的协作。
它是隐藏的,因为Bar 的依赖在Foo 的构造函数或Foo 的方法签名中并不显式。
将一个类视为定义一个向协作者公开的可见合同。方法和构造函数签名是该合同的一部分。方法doSomething() 的主体是隐藏的,因为它是未在合同中公开的类的内部实现细节。我们从签名中只知道有一个名为doSomething() 的方法,其返回类型为void。
举个反例,我们可以重构类以使依赖项显化:
class Foo
{
private readonly Bar bar;
Foo(Bar bar) //the constructor signature is visible
{
this.bar = bar;
}
void doSomething()
{
bar.doSomething();
}
}
在上面的示例中,Bar 被显式定义为构造函数公开签名中的依赖项。
我们也可以这样做:
class Foo
{
void doSomething(Bar bar) //method signature is visible
{
bar.doSomething();
}
}
现在doSomething 方法对Bar 的依赖是可见的,因为它包含在doSomething 的方法签名中。