必知必会的设计原则——迪米特原则
设计原则系列文章
- 必知必会的设计原则——单一职责原则
- 必知必会的设计原则——开放封闭原则
- 必知必会的设计原则——依赖倒置原则
- 必知必会的设计原则——里氏替换原则
- 必知必会的设计原则——接口隔离原则
- 必知必会的设计原则——迪米特原则
- 必知必会的设计原则——合成复用原则
概述
迪米特法则(Law of Demeter )又叫做最少知识原则,即一个对象应该对另一个对象有最少的了解。
迪米特法则的目的在于降低类之间的耦合。由于每个类尽量减少对其他类的依赖,因此,很容易使得系统的功能模块功能独立,相互之间不存在(或很少有)依赖关系。
迪米特原则实际上就是一个类在创建方法和属性时要遵守的法则;
迪米特原则核心指导思想为只和直接朋友通信(成员对象、方法参数、方法返回值;值出现在局部变量的类 ,不是直接朋友)。
案例需求1
实现人关机电脑(人关机电脑一般最起码分为三个步骤,第一步先保存当前的任务,第二步关闭屏幕,第三步关机电源)。
未使用迪米特原则的代码
public class Computer { public void SaveTask() { Console.WriteLine("保存当前电脑任务"); } public void CloseScreen() { Console.WriteLine("关闭屏幕"); } public void ShutDown() { Console.WriteLine("关闭电源"); } } public class Person { public void CloseComputer(Computer computer) {computer.SaveTask(); computer.CloseScreen(); computer.ShutDown(); } }
上面person类中的CloseComputer方法中逻辑不符合迪米特原则,如果关机需要三十步,computer需要提供30个方法,每个方法之间都有相应的绝对顺序。
使用迪米特原则的代码
public class Computer { public void SaveTask() { Console.WriteLine("保存当前电脑任务"); } public void CloseScreen() { Console.WriteLine("关闭屏幕"); } public void ShutDown() { Console.WriteLine("关闭电源"); } public void CloseComputer() { this.SaveTask(); this.CloseScreen(); this.ShutDown(); } } //person类中closecomputer方法中的参数computer为直接朋友,符合迪米特原则 public class Person { public void CloseComputer(Computer computer) { computer.CloseComputer(); } }
上面person类中的CloseComputer方法只负责调用Computer中的CloseComputer方法,如果关机电脑这个需求有其他的变化,computer类里面添加方法或发生逻辑变化,person类始终不会发生改变。
关于迪米特原则很多人听到这个词,估计有点陌生,真实编程中可能这样用过,但不知道其名字,所以我们再来看一个案例需求,加深巩固理解。
案例需求2
分别打印总公司和分公司员工的编号;
未使用迪米特原则的代码
public class HeadOfficeEmployee { public int Id { get; set; } } /// <summary> /// 总公司管理者 /// </summary> public class HeadOfficeManager { /// <summary> /// 获取员工数 /// </summary> /// <returns></returns> public List<HeadOfficeEmployee> GetEmployees() { List<HeadOfficeEmployee> headOffices = new List<HeadOfficeEmployee>(); for (int i = 0; i < 10; i++) { HeadOfficeEmployee headOfficeEmployee = new HeadOfficeEmployee(); headOfficeEmployee.Id = i; headOffices.Add(headOfficeEmployee); } return headOffices; } /// <summary> /// 打印总公司员工id /// </summary> public void Print(BranchOfficeManager branchOfficeManager) { var datas= GetEmployees(); Console.WriteLine("总公司员工Id分别是:" ); foreach (var item in datas) { Console.WriteLine(+item.Id); } //branchOfficeEmployes这个集合对象,是通过局部变量的形式出现在类中的,所以不是我们的直接朋友,故不符合迪米特原则。 var branchOfficeEmployes= branchOfficeManager.GetEmployees(); Console.WriteLine("分公司员工Id分别是:"); foreach (var item in branchOfficeEmployes) { Console.WriteLine(+item.Id); } } }
//C# 控制台调用 BranchOfficeManager branchOfficeManager = new BranchOfficeManager(); new HeadOfficeManager().Print(branchOfficeManager);
以上HeadOfficeManager类中Print方法传递的参数branchOfficeManager是直接朋友,GetEmployee()中返回的集合对象也是直接朋友符合迪米特原则,但branchOfficeManager.GetEmployees()获取的集合branchOfficeEmployes是通过局部变量的形式出现在类中的,所以不符合迪米特原则。
使用迪米特原则改造后的代码
/// <summary> /// 总公司员工 /// </summary> public class HeadOfficeEmployee { public int Id { get; set; } } /// <summary> /// 总公司管理者 /// </summary> public class HeadOfficeManager { /// <summary> /// 获取员工数 /// </summary> /// <returns></returns> public List<HeadOfficeEmployee> GetEmployees() { List<HeadOfficeEmployee> headOffices = new List<HeadOfficeEmployee>(); for (int i = 0; i < 10; i++) { HeadOfficeEmployee headOfficeEmployee = new HeadOfficeEmployee(); headOfficeEmployee.Id = i; headOffices.Add(headOfficeEmployee); } return headOffices; } /// <summary> /// 打印总公司员工id /// </summary> public void Print() { var datas= GetEmployees(); Console.WriteLine("总公司员工Id分别是:" ); foreach (var item in datas) { Console.WriteLine(+item.Id); } }
}
/// <summary> /// 分公司员工类 /// </summary> public class BranchOfficeEmployee { public int Id { get; set; } } /// <summary> /// 分公司员工管理者 /// </summary> public class BranchOfficeManager { public List<BranchOfficeEmployee> GetEmployees() { List<BranchOfficeEmployee> headOffices = new List<BranchOfficeEmployee>(); for (int i = 0; i < 10; i++) { BranchOfficeEmployee headOfficeEmployee = new BranchOfficeEmployee(); headOfficeEmployee.Id = i; headOffices.Add(headOfficeEmployee); } return headOffices; } /// <summary> /// 打印分公司每个员工Id /// </summary> public void Print() { var datas= GetEmployees(); Console.WriteLine("分公司公司员工Id分别是:" ); foreach (var item in datas) { Console.WriteLine(+item.Id); } } }
//C#控制台调用
new HeadOfficeManager().Print(); BranchOfficeManager branchOfficeManager = new BranchOfficeManager(); branchOfficeManager.Print();
总结
迪米特原则在我们日常编码中可能往往最容易被忽略,像案例2这样的需求,尤其写第一种方案的代码的人估计不少,我也写过,慢慢掌握了设计原则后,可以和之前写地代码做下对比,心中会有另一番收获。
作者:realyrare
出处:https://www.cnblogs.com/mhg215/
声援博主:如果您觉得文章对您有帮助,请点击文章末尾的【关注我】吧!
别忘记点击文章右下角的【推荐】支持一波。~~~///(^v^)\\\~~~ .
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
如果您有其他问题,也欢迎关注我下方的公众号,可以联系我一起交流切磋!