05-迪米特法则(LOD 又名: 最少知道原则)
1. 背景
类与类之间的关系越密切,耦合度越大,当一个类发生变化时,对另一个类的影响也越大。
2. 定义
一个类应该对其它类保持最少的了解。
3. 解决方法
尽量降低类与类之间的耦合。
4. 迪米特法则的核心
低耦合
5.迪米特法则深究
只与直接的朋友通信。
每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。
耦合的方式很多,依赖、关联、组合、聚合等。其中,我们称出现成员变量、方法参数、方法返回值中的类为直接的朋友, 而出现在局部变量中的类则不是直接的朋友。也就是说,陌生的类最好不要作为局部变量的形式出现在类的内部。
6. 模拟业务场景
有一个集团公司,下面有很多分公司,现在要求,总公司打印出所有分公司员工的信息。剖析:总公司有很多员工(Employee),分公司里也有很多员工(SubEmployee);总公司与公司的员工、总公司与分公司、分公司与分公司的员工是直接朋友;总公司和分公司的员工不是直接朋友。
先看一个违反了迪米特法则的设计方式:
1 /// <summary> 2 /// 总公司员工类 3 /// </summary> 4 public class Employee 5 { 6 private string id; 7 public void setId(string id) 8 { 9 this.id = id; 10 } 11 public string getId() 12 { 13 return id; 14 } 15 }
1 /// <summary> 2 /// 分公司员工类 3 /// </summary> 4 public class SubEmployee 5 { 6 private string id; 7 public void setId(string id) 8 { 9 this.id = id; 10 } 11 public string getId() 12 { 13 return id; 14 } 15 }
1 /// <summary> 2 /// 分公司管理类 3 /// </summary> 4 public class SubCompanyManager 5 { 6 /// <summary> 7 /// 获取分公司员工信息 8 /// </summary> 9 /// <returns></returns> 10 public List<SubEmployee> getAll() 11 { 12 List<SubEmployee> list = new List<SubEmployee>(); 13 for (int i = 0; i < 5; i++) 14 { 15 SubEmployee sel = new SubEmployee(); 16 sel.setId("分公司员工" + i); 17 list.Add(sel); 18 } 19 return list; 20 } 21 22 }
1 /// <summary> 2 /// 总公司管理类 3 /// </summary> 4 public class CompanyManager 5 { 6 /// <summary> 7 /// 获取总公司员工信息 8 /// </summary> 9 /// <returns></returns> 10 public List<Employee> getAll() 11 { 12 List<Employee> list = new List<Employee>(); 13 for (int i = 0; i < 5; i++) 14 { 15 Employee sel = new Employee(); 16 sel.setId("总公司公司员工" + i); 17 list.Add(sel); 18 } 19 return list; 20 } 21 /// <summary> 22 /// 打印总公司员工信息 23 /// </summary> 24 public void printEmployee() 25 { 26 foreach (var item in this.getAll()) 27 { 28 Console.WriteLine(item.getId()); 29 } 30 } 31 /// <summary> 32 /// 打印分公司员工信息 33 /// </summary> 34 public void printSubEmployee(SubCompanyManager sub) 35 { 36 //这里违背了迪米特法则,直接操控了分公司的员工,总公司和分公司员工不应该是直接关系 37 foreach (var item in sub.getAll()) 38 { 39 Console.WriteLine(item.getId()); 40 } 41 } 42 43 }
1 public static void show() 2 { 3 //模拟业务场景:有一个集团公司,下面有很多分公司,现在要求,总公司打印出所有分公司员工的信息。 4 //剖析:总公司有很多员工(Employee),分公司里也有很多员工(SubEmployee);总公司与公司的员工、总公司与分公司、分公司与分公司的员工是直接朋友; 5 //总公司和分公司的员工不是直接朋友 6 7 //下面先看一个违反了迪米特法则的设计:总公司管理类CompanyManager中直接操作了分公司的员工。 8 //printSubEmployee方法中违背了迪比特法则,违背了迪米特法则,直接操控了分公司的员工,总公司和分公司不应该是直接关系 9 CompanyManager cManager = new CompanyManager(); 10 cManager.printSubEmployee(new SubCompanyManager()); 11 12 }
总结:总公司管理类CompanyManager中直接操作了分公司的员工。printSubEmployee方法中违背了迪比特法则,违背了迪米特法则,直接操控了分公司的员工,总公司和分公司不应该是直接关系。
改进后的设计:给SubCompanyManager类中添加打印分公司员工的方法,然后再CompanyManager中,直接调用打印分公司员工的方法,这样就是总公司依赖了分公司,得到了分公司员工的信息,并没有直接依赖分公司员工。
1 /// <summary> 2 /// 分公司管理类 3 /// </summary> 4 public class SubCompanyManager 5 { 6 /// <summary> 7 /// 获取分公司员工信息 8 /// </summary> 9 /// <returns></returns> 10 public List<SubEmployee> getAll() 11 { 12 List<SubEmployee> list = new List<SubEmployee>(); 13 for (int i = 0; i < 5; i++) 14 { 15 SubEmployee sel = new SubEmployee(); 16 sel.setId("分公司员工" + i); 17 list.Add(sel); 18 } 19 return list; 20 } 21 22 /// <summary> 23 /// 新增:打印分公司员工信息,为了满足迪米特法则 24 /// </summary> 25 public void printSubEmployee() 26 { 27 foreach (var item in this.getAll()) 28 { 29 Console.WriteLine(item.getId()); 30 } 31 } 32 33 }
1 /// <summary> 2 /// 总公司管理类 3 /// </summary> 4 public class CompanyManager 5 { 6 /// <summary> 7 /// 打印分公司员工信息2 8 /// </summary> 9 public void printSubEmployee2(SubCompanyManager sub) 10 { 11 //这里总公司直接依赖分公司,得到了分公司员工信息,遵循了迪米特法则 12 sub.printSubEmployee(); 13 } 14 15 }
public static void show() { //模拟业务场景:有一个集团公司,下面有很多分公司,现在要求,总公司打印出所有分公司员工的信息。 //剖析:总公司有很多员工(Employee),分公司里也有很多员工(SubEmployee);总公司与公司的员工、总公司与分公司、分公司与分公司的员工是直接朋友; //总公司和分公司的员工不是直接朋友 //下面先看一个违反了迪米特法则的设计:总公司管理类CompanyManager中直接操作了分公司的员工。 //printSubEmployee方法中违背了迪比特法则,违背了迪米特法则,直接操控了分公司的员工,总公司和分公司不应该是直接关系 CompanyManager cManager = new CompanyManager(); cManager.printSubEmployee(new SubCompanyManager()); //下面是改进后的方案,遵循迪米特法则,给SubCompanyManager类中添加打印分公司员工的方法,然后再CompanyManager中,直接调用打印分公司员工的方法 //这样就是总公司依赖了分公司,得到了分公司员工的信息,并没有直接依赖分公司员工 Console.WriteLine("--------------------下面是采用迪米特法则改进后的方案-----------------------"); cManager.printSubEmployee2(new SubCompanyManager()); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?