迪米特法则(Demeter Princlple)
1.基本介绍
- 一个对象应该对其他对象保持最小的了解
- 类与类关系越密切,耦合度越大
- 迪米特法则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。
- 对于被依赖的类不管多复杂,都尽量将逻辑封装在类的内部,对外除了提供的public方法,不对外泄露任何信息。
- 只与直接的朋友通信。
- 什么是直接的朋友?:每个对象都会与其他对象有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式有很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。
简单来说,就是最好不要出现以下情况
class A{
public void func1(){
B b = new B(); // 陌生的B类以局部变量的形式出现在了类内部
}
}
2.一个违反迪米特的实际案例
一个学校,员工分为学校管理层和各个学院老师,要求先打印出学校管理层的员工ID再打印出各个学院老师的ID。
/*
* 学校管理层员工实体类
*/
class ManagerEmployee(){
// 员工ID
private String id;
public void setId(String id){ this.id = id }
public String getId(){ return id }
}
/*
* 学院老师实体类
*/
class TeacherEmployee(){
// 员工ID
private String id;
public void setId(String id){ this.id = id }
public String getId(){ return id }
}
/*
* 学校管理层员工数据源,模拟构造3个学校管理人员
*/
class ManagerEmployeeDataSource(){
public List<ManagerEmployee> getAllManagerEmployee(){
List<ManagerEmployee> managers = new ArraryList<>();
for(int 1=0; i<3; i++){
ManagerEmployee m = new ManagerEmployee();
m.setId(i);
managers.add(m);
}
return managers ;
}
}
/*
* 学院老师员工数据源,模拟构造5个学院老师人员
* 同时还有打印学校管理层及学院老师信息的方法
*/
class TeacherEmployeeDataSource(){
// 构造老师信息
public List<TeacherEmployee> getAllTeacherEmployee(){
List<TeacherEmployee> teachers = new ArraryList<>();
for(int 1=0; i<5; i++){
TeacherEmployeem t = new TeacherEmployee();
t.setId(i);
teachers.add(t);
}
return teachers;
}
// 打印信息
public void printAll(ManagerEmployeeDataSource mds){
List<ManagerEmployee> managers = mds.getAllManagerEmployee();
sout("------管理层信息------");
for(ManagerEmployee m : managers ){
sout(m.getId());
}
List<TeacherEmployee> teachers = this.getAllTeacherEmployee();
sout("------学院老师信息------");
for(TeacherEmployee t: teachers){
sout(t.getId());
}
}
}
public Do{
public static void main(){
TeacherEmployeeDataSource ts = new TeacherEmployeeDataSource();
ts.printAll(new ManagerEmployeeDataSource());
}
}
先分析一下以上的代码中哪些是直接朋友:
ManagerEmployee不是类TeacherEmployeeDataSource的直接朋友,所以违背了迪米特法则。
3.符合迪米特法则的修改
改进的思路:以上的问题是学校管理层类ManagerEmployee类不是学院老师数据构造类TeacherEmployeeDataSource类的直接朋友,违背了迪米特法则,即要避免出现这种情况。
- 将打印学校管理层信息的代码挪到学校管理层数据构造类中
这里也就是我们开头说的对于被依赖的类不管多复杂,都尽量将逻辑封装在类的内部,对外除了提供的public方法,不对外泄露任何信息
/*
* 学校管理层员工数据源,模拟构造3个学校管理人员
*/
class ManagerEmployeeDataSource(){
public List<ManagerEmployee> getAllManagerEmployee(){
List<ManagerEmployee> managers = new ArraryList<>();
for(int 1=0; i<3; i++){
ManagerEmployee m = new ManagerEmployee();
m.setId(i);
managers.add(m);
}
return managers ;
}
// 打印信息
public void printAllManager(){
List<ManagerEmployee> managers = getAllManagerEmployee();
sout("------管理层信息------");
for(ManagerEmployee m : managers ){
sout(m.getId());
}
}
}
- 学院老师数据构造类中保留打印学院老师信息的代码
/*
* 学院老师数据源,模拟构造5个学院老师
*/
class TeacherEmployeeDataSource(){
// 构造老师信息
public List<TeacherEmployee> getAllTeacherEmployee(){
List<TeacherEmployee> teachers = new ArraryList<>();
for(int 1=0; i<5; i++){
TeacherEmployeem t = new TeacherEmployee();
t.setId(i);
teachers.add(t);
}
return teachers;
}
// 打印信息
public void printAll(ManagerEmployeeDataSource mds){
// 打印所有管理层
mds.printAllManager();
// 打印所有学院老师
List<TeacherEmployee> teachers = getAllTeacherEmployee();
sout("------学院老师信息------");
for(TeacherEmployee t: teachers){
sout(t.getId());
}
}
}
- 使用不需要修改
public Do{
public static void main(){
TeacherEmployeeDataSource ts = new TeacherEmployeeDataSource();
ts.printAll(new ManagerEmployeeDataSource());
}
}
- 再来分析下之前违背迪米特法则的代码