显式依赖关系原则

Explicit Dependencies Principle

定义

方法和类应明确要求(通常通过方法参数或构造函数参数)它们所需的任何协作对象, 以便正常运行.

依赖项

如果您的类需要其他类来执行其操作, 那么这些其他类就是依赖项.

隐式依赖项

如果这些依赖项仅存在于类内部的代码中, 而不存在于其公共接口中, 则它们是隐式的.

显式依赖项

对于类的依赖项, 显示依赖项最常出现在对象的构造函数中; 对于更多本地依赖项, 显式依赖项通常出现在特定方法的参数列表中.

隐式依赖的缺点

隐式依赖关系的类比具有显式依赖关系的类的维护成本更高. 它们更难测试, 因为他们与协作者的耦合更紧密. 更难以分析副作用, 因为必须搜索整个类的代码库以查找对象实例化或对静态方法的调用. 与合作者的耦合更紧密, 导致设计更加僵化和脆弱.

显式依赖的优点

非常清楚的说明了执行特定职能所需的条件. 它们倾向于遵循最小意外原则, 减少修改代码影响的范围. 无论是在生产中还是在测试或debug过程中, 显式依赖项都可以轻松的替换为其他实现. 这使得它们更容易维护并且更愿意改变.

示例

示例1-隐式依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class User
{
public string Name;
}

public static class Context
{
public static User CurrentUser;

public static User GetCurrentUser()
{
return CurrentUser;
}
}

public class Client
{
public string Login()
{
return $"用户:{Context.GetCurrentUser().Name} 已登陆!";
}
}

internal class Program
{
public static void Main(string[] args)
{
var user = new User
{
Name = "A"
};

Context.CurrentUser = user;

var client = new Client();
Console.WriteLine(client.Login());
Console.ReadLine();
}
}

示例1中, Client对User对象的依赖是在Context静态类中, 并没有在公共接口中, 是隐式依赖项. 在Main中调用的时候, 并不能直观的了解到client和创建的user有什么联系, 需要查看内部具体的代码, 代码间的隔离性很差.

示例2-显式依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class User
{
public string Name;
}

public class Client
{
public string Login(User user)
{
return $"用户:{user.Name} 已登陆!";
}
}

internal class Program
{
public static void Main(string[] args)
{
var user = new User()
{
Name = "A"
};

var client = new Client();
Console.WriteLine(client2.Login(user));
Console.ReadLine();
}
}

在示例2中, 对于示例1进行了改进. 不再将user对象的引用存储在Context中去隐式传递依赖项, 而是直接将user作为client.Login方法的参数传递依赖项, 能更加直观的看出关联关系, 且对于Login方法内部的代码也更加具有隔离性.

相关源码