# 迪米特法则(Law of Demeter)

基本介绍:

  1. 一个对象应该改对其他对象保持最少的了解

  2. 类与类的关系越密切,耦合度越大

  3. 迪米特法则又叫最少知道原则,简单说就是一个类对自己依赖的类知道的越少越好,被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部,对外只提供public方法,不对外泄露任何信息。

  4. 迪米特法则有个更简单的定义:只与直接朋友通信

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

# 迪米特法则例子

有一个学校,下属有各个学院和总部,现要求打印出学校总部员工ID和学院员工的ID

import java.util.ArrayList;
import java.util.List;
//客户端
public class Main {
	public static void main(String[] args) {
		SchoolManager schoolManager = new SchoolManager();
		schoolManager.printAllEmployee(new CollegeManager());
	}
}
//学校总部员工
class Employee {
	private String id ;
	public void setId(String id) {
		this.id = id ;
	}
	public String getId() {
		return id ;
	}
}
//学院的员工
class CollegeEmployee {
	private String id;
	public void setId(String id) {
		this.id = id ;
	}
	public String getId() {
		return id ;
	}
}
//管理学院员工
class CollegeManager {
	public List<CollegeEmployee> getAllEmployee() {
		List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
		for(int i = 0;i < 10; i++) {
			CollegeEmployee emp = new CollegeEmployee();
			emp.setId("学院员工id:" + i);
			list.add(emp);
		}
		return list;
	}
}
//管理学校员工
class SchoolManager {
	public List<Employee> getAllEmployee() {
		List<Employee> list = new ArrayList<Employee>();
		for(int i = 0; i < 5; i++) {
			Employee emp = new Employee();
			emp.setId("学校总部员工:" + i);
			list.add(emp);
		}
		return list;
	}
	//打印所有的员工
	void printAllEmployee(CollegeManager sub) {
		List<CollegeEmployee> list1 = sub.getAllEmployee();
		System.out.println("---------学院员工----------");
		for(CollegeEmployee e : list1) {
			System.out.println(e.getId());
		}
		List<Employee> list2 = this.getAllEmployee();
		System.out.println("----------学校总部员工--------");
		for (Employee e : list2) {
			System.out.println(e.getId());
		}
	}
}

现在来分析一下这个代码,符不符合迪米特法则。

迪米特法则的规则是,一个类只与它的直接朋友进行交流,耦合类的对象的直接朋友是,成员变量,方法参数,方法返回值,除了以上三种都不是直接朋友。

来看一下这段代码,传入参数的类型是CollegeManager,按照规则它是本类的直接朋友,再看CollegeEmployee他们在方法体中,是局部变量,所以并不是本类的直接朋友。为什么Employee是直接朋友?那是因为在上一个方法中Employee是作为方法返回值使用的。那么CollegeEmployee这部分代码放到哪里呢?传入参数是sub,所以相当于把输出这件事情交给了sub去处理,所以把他们封装到CollegeManager中。

	void printAllEmployee(CollegeManager sub) {
		List<CollegeEmployee> list1 = sub.getAllEmployee();
		System.out.println("---------学院员工----------");
		for(CollegeEmployee e : list1) {
			System.out.println(e.getId());
		}
		List<Employee> list2 = this.getAllEmployee();
		System.out.println("----------学校总部员工--------");
		for (Employee e : list2) {
			System.out.println(e.getId());
		}
	}

改正代码后,其实代码逻辑也更符合现实生活一点,因为一个学院总会有自己学院员工名单的,不可能什么都交给学校去做,而一个学校的权力肯定比学院要大一点,有权去知道这个学院有多少员工。

import java.util.ArrayList;
import java.util.List;
//客户端
public class Main {
	public static void main(String[] args) {
		SchoolManager schoolManager = new SchoolManager();
		schoolManager.printAllEmployee(new CollegeManager());
	}
}
//学校总部员工
class Employee {
	private String id ;
	public void setId(String id) {
		this.id = id ;
	}
	public String getId() {
		return id ;
	}
}
//学院的员工
class CollegeEmployee {
	private String id;
	public void setId(String id) {
		this.id = id ;
	}
	public String getId() {
		return id ;
	}
}
//管理学院员工
class CollegeManager {
	public List<CollegeEmployee> getAllEmployee() {
		List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
		for(int i = 0;i < 10; i++) {
			CollegeEmployee emp = new CollegeEmployee();
			emp.setId("学院员工id:" + i);
			list.add(emp);
		}
		return list;
	}
	public void printAllEmployee() {
		List<CollegeEmployee> list1 = this.getAllEmployee();
		System.out.println("---------学院员工----------");
		for(CollegeEmployee e : list1) {
			System.out.println(e.getId());
		}
	}
}
//管理学校员工
class SchoolManager {
	public List<Employee> getAllEmployee() {
		List<Employee> list = new ArrayList<Employee>();
		for(int i = 0; i < 5; i++) {
			Employee emp = new Employee();
			emp.setId("学校总部员工:" + i);
			list.add(emp);
		}
		return list;
	}
	//打印所有的员工
	void printAllEmployee(CollegeManager sub) {
		sub.printAllEmployee();
		List<Employee> list2 = this.getAllEmployee();
		System.out.println("----------学校总部员工--------");
		for (Employee e : list2) {
			System.out.println(e.getId());
		}
	}
}