迪米特原则
1.1 迪米特法则定义
迪米特法则又称为最少知道原则,也就是说一个对象类对其他对象来说,知道的越少越好,两个类之间不要有过多的耦合关系,保持最少关联性。 迪米特法则有一句经典语录:只和朋友通信,不和陌生人说话。也就是说有关联的内要内聚,没有直接关系的类要低耦合。
2.1 模拟场景
通过模拟学生、老师、校长之间的关系来模拟迪米特法则。老师负责具体某一个学生的学习情况,而校长只会关系每个班级的总体成绩,不会具体过问某一个学生的具体成绩。 如果校长想要知道一个班级的总体成绩是直接找每个学生要再进行统计呢,还是应该向老师要呢?显然应该是直接向老师要一个班级的总体成绩。我们在实际开发,容易忽略这样的真实情况,开发出逻辑错误的程序。
2.2 违背原则方案
首先定义一个学生类,主要有学生姓名、考试排名、总分。
public class Student {
private String name;
private int rank;
private double grade;
public Student() {
}
public Student(String name, int rank, double grade) {
this.name = name;
this.rank = rank;
this.grade = grade;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getRank() {
return rank;
}
public void setRank(int rank) {
this.rank = rank;
}
public double getGrade() {
return grade;
}
public void setGrade(double grade) {
this.grade = grade;
}
}
之后再定义出老师类,在老师类中初始化学生信息,以及提供基本信息获取接口
public class Teacher {
private String name;
private String clazz;
private static List<Student> studentList;
public Teacher() {
}
public Teacher(String name, String clazz) {
this.name = name;
this.clazz = clazz;
}
static {
studentList=new ArrayList<>();
studentList.add(new Student("小明",10,450));
studentList.add(new Student("花花",4,553));
studentList.add(new Student("小明",18,354));
studentList.add(new Student("小明",7,581));
studentList.add(new Student("小明",20,300));
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public static List<Student> getStudentList() {
return studentList;
}
public static void setStudentList(List<Student> studentList) {
Teacher.studentList = studentList;
}
}
在老师类中初始化了学生信息,同时提供了简单的接口。下面定义校长类,校长管理全局,并在校长类中获取学生人数、总分、平均分等。
public class Principal {
private Teacher teacher = new Teacher("王丽", "5年级1班");
public Map<String, Object> queryClazzInfo(String clazzId) {
int stuCount = clazzStudentCount();
double averageScore = clazzAverageScore();
double totalScore = clazzTotalScore();
Map<String, Object> map = new HashMap<>();
map.put("老师", teacher.getName());
map.put("班级", teacher.getClazz());
map.put("人数", stuCount);
map.put("平均分", averageScore);
map.put("总分", totalScore);
return map;
}
private int clazzStudentCount() {
return teacher.getStudentList().size();
}
public double clazzTotalScore() {
return teacher.getStudentList()
.stream()
.map(Student::getGrade).mapToDouble(Double::doubleValue).sum();
}
public double clazzAverageScore() {
double sum = teacher.getStudentList()
.stream()
.map(Student::getGrade).mapToDouble(Double::doubleValue).sum();
return sum / teacher.getStudentList().size();
}
}
以上就是通过校长管理所有学生,老师只提供非常简单的信息。虽然可以查看到结果,但是违背了迪米特法则,因为校长需要了解每个学生的情况。如果所有班级类都让校长类进行统计,代码就会变得非常臃肿,也不易于扩展和维护。
2.3 迪米特法则改善代码
从以上实现方式我们发现,不该让校长直接管理学生,应该老师管理学生,校长管理老师。所以应该老师类通过学生信息查询服务。下面我们把校长要的信息交给老师类去处理。
public class Teacher {
private String name;
private String clazz;
private static List<Student> studentList;
public Teacher() {
}
public Teacher(String name, String clazz) {
this.name = name;
this.clazz = clazz;
}
static {
studentList=new ArrayList<>();
studentList.add(new Student("小明",10,450));
studentList.add(new Student("花花",4,553));
studentList.add(new Student("小明",18,354));
studentList.add(new Student("小明",7,581));
studentList.add(new Student("小明",20,300));
}
public int clazzStudentCount() {
return getStudentList().size();
}
public double clazzTotalScore() {
return getStudentList()
.stream()
.map(Student::getGrade)
.mapToDouble(Double::doubleValue).sum();
}
public double clazzAverageScore() {
double sum = getStudentList()
.stream()
.map(Student::getGrade)
.mapToDouble(Double::doubleValue).sum();
return sum / getStudentList().size();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public static List<Student> getStudentList() {
return studentList;
}
public static void setStudentList(List<Student> studentList) {
Teacher.studentList = studentList;
}
}
使用迪米特法则后,将原来违背迪米特法则的服务接口交给老师类去处理。这样每一位老师都会提供对应的功能,校长类只需要调用即可,而不需要了解每一位学生的分数。
接来看校长类如何使用,如下所示:
public class Principal {
private Teacher teacher = new Teacher("王丽", "5年级1班");
public Map<String, Object> queryClazzInfo(String clazzId) {
int stuCount = teacher.clazzStudentCount();
double averageScore = teacher.clazzAverageScore();
double totalScore = teacher.clazzTotalScore();
Map<String, Object> map = new HashMap<>();
map.put("老师", teacher.getName());
map.put("班级", teacher.getClazz());
map.put("人数", stuCount);
map.put("平均分", averageScore);
map.put("总分", totalScore);
return map;
}
}
校长类直接调用老师类服务接口即可,这样一来整个功能逻辑就非常清晰了。
下面验证程序结果:
public class Test {
public static void main(String[] args) {
Principal principal = new Principal();
Map<String, Object> map = principal.queryClazzInfo("5年级1班");
System.out.println("查询结果:"+map);
}
}
查询结果:{总分=2238.0, 班级=5年级1班, 老师=王丽, 人数=5, 平均分=447.6}
以上就是迪米特法则的基本使用。
|