设计模式七大原则之迪米特法则(Demeter Principle)

迪米特法则(LOD:Law of Demeter/Demeter Principle),又叫最少知道原则(LKP:Least Knowledge Principle),即一个类对自己依赖的类知道的越少越好。

其实,迪米特法则反应出来的核心思想还是编程中总的原则:低耦合,高内聚。类与类关系越密切,耦合度越大,如果实际的需求发生改变,我们需要更改软件,当一个类改动时,另一个或多个类跟这个类的关系越密切(耦合度越高),受到的影响也越大。迪米特法则还有一个更简单的定义:只与直接的朋友通信。

点击显/隐

直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。

举一个打印员工绩效的例子

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/**
* @author sunys
*/
public class Demeterprinciple {
public static void main(String[] args) {
DevelopmentCenterManage.showPerformance();
}

/**
* 开发中心员工
*/
private static class DevelopmentCenter{
private String name;
private String performance;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPerformance() {
return performance;
}

public void setPerformance(String performance) {
this.performance = performance;
}
}
/**
* 开发中心的开发一部员工
*/
private static class FirstDepartment{
private String name;
private String performance;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPerformance() {
return performance;
}

public void setPerformance(String performance) {
this.performance = performance;
}
}

/**
* 开发中心的开发一部员工管理类
*/
private static class FirstDepartmentManager{
private static List<FirstDepartment> getFirstDepartment(){
List<FirstDepartment> firstDepartmentList = new ArrayList<FirstDepartment>();
FirstDepartment firstDepartment = new FirstDepartment();
firstDepartment.setName("zhangsan");
firstDepartment.setPerformance("A");
firstDepartmentList.add(firstDepartment);
return firstDepartmentList;
}
}
/**
* 开发中心管理类
*/
private static class DevelopmentCenterManage{
/**
* 获取开发中心所有员工绩效
* @return
*/
private static List<DevelopmentCenter> getDevelopmentCenter(){
List<DevelopmentCenter> developmentCenterList = new ArrayList<DevelopmentCenter>();
DevelopmentCenter developmentCenter = new DevelopmentCenter();
developmentCenter.setName("zhangsan");
developmentCenter.setPerformance("A");
developmentCenterList.add(developmentCenter);
return developmentCenterList;
}

/**
* 打印绩效
*/
private static void showPerformance(){
List<DevelopmentCenter> developmentCenterList = getDevelopmentCenter();
for (DevelopmentCenter developmentCenter : developmentCenterList ){
System.out.println("name:"+ developmentCenter.getName() + " performance:"+ developmentCenter.getPerformance());
}
// 开发中心的开发一部员工普遍绩效比较优秀也要打印出来
// 但此处引入了DevelopmentCenterManage的非直接朋友类FirstDepartment,违反了迪米特法则
List<FirstDepartment> firstDepartmentList = FirstDepartmentManager.getFirstDepartment();
for (FirstDepartment firstDepartment : firstDepartmentList) {
System.out.println("name:"+ firstDepartment.getName() + " performance:"+ firstDepartment.getPerformance());
}
}
}
}

在上面的例子中,我们想打印出开发中心所有员工的绩效情况,但是由于开发中心的开发一部员工普遍表现优秀,所以也想一起打印出来,但共用了DevelopmentCenterManage类的打印方法,最终导致引入了DevelopmentCenterManage的非直接朋友类FirstDepartment,违反了迪米特法则,这样显然是增加了不必要的耦合。因此,改进如下:

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/**
* @author sunys
*/
public class Demeterprinciple1 {
public static void main(String[] args) {
DevelopmentCenterManage.showPerformance();
}

/**
* 开发中心员工
*/
private static class DevelopmentCenter{
private String name;
private String performance;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPerformance() {
return performance;
}

public void setPerformance(String performance) {
this.performance = performance;
}
}
/**
* 开发中心的开发一部员工
*/
private static class FirstDepartment{
private String name;
private String performance;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getPerformance() {
return performance;
}

public void setPerformance(String performance) {
this.performance = performance;
}
}

/**
* 开发中心的开发一部员工管理类
*/
private static class FirstDepartmentManager{
private static List<FirstDepartment> getFirstDepartment(){
List<FirstDepartment> firstDepartmentList = new ArrayList<FirstDepartment>();
FirstDepartment firstDepartment = new FirstDepartment();
firstDepartment.setName("zhangsan");
firstDepartment.setPerformance("A");
firstDepartmentList.add(firstDepartment);
return firstDepartmentList;
}

/**
* 增加独立的打印方法
*/
private static void showFirstDepartmentPerformance(){
List<FirstDepartment> firstDepartmentList = getFirstDepartment();
for (FirstDepartment firstDepartment : firstDepartmentList) {
System.out.println("name:"+ firstDepartment.getName() + " performance:"+ firstDepartment.getPerformance());
}
}
}
/**
* 开发中心管理类
*/
private static class DevelopmentCenterManage{
/**
* 获取开发中心所有员工绩效
* @return
*/
private static List<DevelopmentCenter> getDevelopmentCenter(){
List<DevelopmentCenter> developmentCenterList = new ArrayList<DevelopmentCenter>();
DevelopmentCenter developmentCenter = new DevelopmentCenter();
developmentCenter.setName("zhangsan");
developmentCenter.setPerformance("A");
developmentCenterList.add(developmentCenter);
return developmentCenterList;
}

/**
* 打印绩效
*/
private static void showPerformance(){
List<DevelopmentCenter> developmentCenterList = getDevelopmentCenter();
for (DevelopmentCenter developmentCenter : developmentCenterList ){
System.out.println("name:"+ developmentCenter.getName() + " performance:"+ developmentCenter.getPerformance());
}

// 遵循迪米特法则,这里调用FirstDepartmentManager类自己封装的打印方法,
// 不在引入非直接朋友类FirstDepartment
FirstDepartmentManager.showFirstDepartmentPerformance();
}
}
}

迪米特法则的核心是降低类之间的耦合,在实际开发的过程中,对于被依赖的类不管多么复杂,我们都应尽量将逻辑封装在类的内部,对外除了提供的public方法,不对外泄露任何信息。当然,这不是要求完全没有依赖关系,使用迪米特法则时我们应当根据实际情况权衡,尽量降低类间(对象间)耦合关系。

附:本次演示的项目地址
https://github.com/syshlang/java-design-principle