迪米特法则又称之为最小认知法则(LKP) ,意思是一个类应该最自己耦合或者调用的类,知道越少越好,被调用的类内部如何复杂,调用方均不用理会,不关心其他的问题。迪米特法则还有一个比较有意思的英文别称: 只和自己的直接朋友通讯。 什么是直接朋友呢? 两个对象之间的耦合就成为朋友关系,这种关系的类型有很多,例如组合、聚合、依赖等。

5.1 点名示例

老师 Teacher 让组长 GroupLeader 去统计组内的学生的数量,直接写出的简单设计类图如下:

5、迪米特法则(LKP) - 图1 大致代码如下:

  1. public class LKP {
  2. public static void main(String[] args) {
  3. Teacher teacher = new Teacher();
  4. teacher.command(new GroupLeader());
  5. }
  6. static class Teacher {
  7. public void command(GroupLeader leader) {
  8. List<Student> stuList = new ArrayList<>();
  9. // 增加学生
  10. int count = leader.count(stuList);
  11. System.out.println("学生有" + count + "个");
  12. }
  13. }
  14. static class GroupLeader {
  15. public int count(List<Student> stuList) {
  16. return stuList.size();
  17. }
  18. }
  19. static class Student {
  20. private String name;
  21. }
  22. }

5.2 代码改进

基于上面的分析,笔者认为,Teacher不应对Student类进行直接依赖,只需要将这部分内部逻辑交给 GroupLeader即可,修改后的类图如下:

5、迪米特法则(LKP) - 图2 代码如下,修改后的代码中可以明显的看到,Teacher 类不在对Student直接依赖。

  1. public class LKP2 {
  2. public static void main(String[] args) {
  3. Teacher teacher = new Teacher();
  4. GroupLeader groupLeader = new GroupLeader();
  5. teacher.command(groupLeader);
  6. }
  7. static class Teacher {
  8. public void command(GroupLeader leader) {
  9. int count = leader.count();
  10. System.out.println("学生有" + count + "个");
  11. }
  12. }
  13. static class GroupLeader {
  14. private List<Student> stuList;
  15. public void setStuList() {
  16. List<Student> list = new ArrayList<>();
  17. // 调用其他服务查询学生列表
  18. this.stuList = list;
  19. }
  20. public int count() {
  21. return stuList.size();
  22. }
  23. }
  24. static class Student {
  25. private String name;
  26. }
  27. }

5.3 最佳实践

  • 尽量少的依赖非必须的类
  • [x] 不要过多的调用直接朋友的方法,调用过多,可以将该方法封装在依赖的类中,比如下面的逻辑.

  • 判断手机是否是一个好手机,需要判断价格是否便宜 & 质量好 & 新款手机

  1. public class LKP3 {
  2. public static void main(String[] args) {
  3. Phone phone = new Phone();
  4. boolean result = !phone.isCheap() && phone.isGood() && phone.isNewVersion();
  5. System.out.println("手机是一款好手机吗?" + result);
  6. }
  7. static class Phone {
  8. public boolean isCheap() {
  9. return false;
  10. }
  11. public boolean isGood() {
  12. return true;
  13. }
  14. public boolean isNewVersion() {
  15. return true;
  16. }
  17. }
  18. }

事实上,上面的代码存在两个问题:

  • 暴露过多的public方法
  • 过多的依赖直接朋友,多次访问直接朋友的方法,修改后的代码如下
  1. package com.zhoutao123.design.principle;
  2. public class LKP3 {
  3. public static void main(String[] args) {
  4. Phone phone = new Phone();
  5. System.out.println("手机是一款好手机吗?" + phone.check());
  6. }
  7. static class Phone {
  8. private boolean isCheap() {
  9. return false;
  10. }
  11. private boolean isGood() {
  12. return true;
  13. }
  14. private boolean isNewVersion() {
  15. return true;
  16. }
  17. public boolean check() {
  18. return !this.isCheap() && this.isGood() && this.isNewVersion();
  19. }
  20. }
  21. }