赞
踩
迪米特法(Law Of Demeter , LoD)则又叫最少知道原则(Least Knowledge Principle),最早是在1987年由美国Northeastern University的Ian Holland提出。
通俗的来讲,就是一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类来说,无论逻辑多么复杂,都尽量地的将逻辑封装在类的内部,对外除了提供的public方法,不对外泄漏任何信息。
迪米特法有一个经典语录:只与朋友通信,不和陌生人说话。
首先来解释一下什么是朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。
耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友,而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。
学生、老师、校长 来说明迪米特法则。
老师需要负责具体某一个学生的学习情况, 校长只关心老师所在班级的总体成绩,不会过问具体某一个学生的学习情况。
试想一下,校长想知道一个班级的总分和平均分,是应该找老师要 还是 跟每一个学生要然后再进行统计呢? 显然是应该跟老师要。 实际开发中,很容易犯这种错误。
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; } // set get }
在教师类中初始化学生的信息,提供基本的信息获取接口。
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, 589)); studentList.add(new Student("豆豆", 54, 356)); studentList.add(new Student("秋雅", 23, 439)); studentList.add(new Student("皮皮", 2, 665)); studentList.add(new Student("蛋蛋", 19, 502)); } public static List<Student> getStudentList() { return studentList; } public String getName() { return name; } public String getClazz() { return clazz; } }
【校长类】
校长管理全局,并在校长类中获取学生人数、总分、平均分等
public class Principal { private Teacher teacher = new Teacher("丽华", "3年1班"); // 查询班级信息,总分数、学生人数、平均值 public Map<String, Object> queryClazzInfo(String clazzId) { // 获取班级信息;学生总人数、总分、平均分 int stuCount = clazzStudentCount(); double totalScore = clazzTotalScore(); double averageScore = clazzAverageScore(); // 组装对象,实际业务开发会有对应的类 Map<String, Object> mapObj = new HashMap<>(); mapObj.put("班级", teacher.getClazz()); mapObj.put("老师", teacher.getName()); mapObj.put("学生人数", stuCount); mapObj.put("班级总分数", totalScore); mapObj.put("班级平均分", averageScore); return mapObj; } // 总分 public double clazzTotalScore() { double totalScore = 0; for (Student stu : teacher.getStudentList()) { totalScore += stu.getGrade(); } return totalScore; } // 平均分 public double clazzAverageScore(){ double totalScore = 0; for (Student stu : teacher.getStudentList()) { totalScore += stu.getGrade(); } return totalScore / teacher.getStudentList().size(); } // 班级人数 public int clazzStudentCount(){ return teacher.getStudentList().size(); } }
以上是通过校长管理所有的学生信息, 老师只是提供了非常简单的信息。虽然可以查询到结果,但违背了迪米特法则,因为校长需要了解每个学生的情况。 如果所有的班级都让校长类去统计,代码将会变得非常的臃肿,也不易于扩展和维护。
看下单测
@Test
public void test_Principal() {
Principal principal = new Principal();
Map<String, Object> map = principal.queryClazzInfo("3年1班");
logger.info("查询结果:{}", JSON.toJSONString(map));
}
上述的实现我们可以发现,不应该让校长直接管理学生,校长应该管理老师,由老师提供相应的学生信息查询服务,那么接下来我们把校长要的信息交给老师类去处理。
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, 589)); studentList.add(new Student("豆豆", 54, 356)); studentList.add(new Student("秋雅", 23, 439)); studentList.add(new Student("皮皮", 2, 665)); studentList.add(new Student("蛋蛋", 19, 502)); } // 总分 public double clazzTotalScore() { double totalScore = 0; for (Student stu : studentList) { totalScore += stu.getGrade(); } return totalScore; } // 平均分 public double clazzAverageScore(){ double totalScore = 0; for (Student stu : studentList) { totalScore += stu.getGrade(); } return totalScore / studentList.size(); } // 班级人数 public int clazzStudentCount(){ return studentList.size(); } public String getName() { return name; } public String getClazz() { return clazz; } }
使用迪米特法则 后,把燕来违背迪米特法则的服务接口交给老师类处理,这样每一位老师都会提供相应的功能,校长只需要调用即可,不需要了解每一位学生的分数。
那看看校长类如何使用的
public class Principal { private Teacher teacher = new Teacher("丽华", "3年1班"); // 查询班级信息,总分数、学生人数、平均值 public Map<String, Object> queryClazzInfo(String clazzId) { // 获取班级信息;学生总人数、总分、平均分 int stuCount = teacher.clazzStudentCount(); double totalScore = teacher.clazzTotalScore(); double averageScore = teacher.clazzAverageScore(); // 组装对象,实际业务开发会有对应的类 Map<String, Object> mapObj = new HashMap<>(); mapObj.put("班级", teacher.getClazz()); mapObj.put("老师", teacher.getName()); mapObj.put("学生人数", stuCount); mapObj.put("班级总分数", totalScore); mapObj.put("班级平均分", averageScore); return mapObj; } }
校长直接调用老师的接口,并回获取相应的结果信息。 这样一来,整个功能逻辑就非常清晰了。
单测如下
@Test
public void test_Principal() {
Principal principal = new Principal();
Map<String, Object> map = principal.queryClazzInfo("3年1班");
logger.info("查询结果:{}", JSON.toJSONString(map));
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。