|
一、迪米特法则
迪米特法则(Law of Demeter)又叫作最少知道原则(The Least Knowledge Principle),一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话。
1、目的
降低类与类之间的耦合度
2、定义
迪米特法则又叫最少知道原则,即一个类对自己依赖的类知道的越少越好,对于依赖的类不管有多复杂,都尽量将逻辑封装在类的内部,对外除了提供public方法,不泄漏任何信息。
更简单的说法:只与直接朋友通信。
直接朋友:每个对象都会与其它对象有耦合关系,耦合的方式有很多,依赖、关联、组合、聚合等。我们称出现在成员变量,方法参数,方法返回值中的类称为直接朋友,而出现在局部变量中的类不能称为直接朋友,也就是说,陌生的类不要以局部变量的形式出现在类的内部。
3、注意事项和细节
- 类的结构设计上,尽量降低类成员的访问权限;
- 在类的设计上,优先考虑将一个类设计成不变类;
- 在类的引用上,将引起其他类的次数降到最低;
- 不暴露类的属性成员,而应该提供相应的访问器(getter、setter);
- 谨慎使用序列化(serializable)功能;
过分的使用迪米特原则,会产生大量这样的中介和传递类,类之间需要通信就通过第三方转发的方式,就会造成系统的不同模块之间的通信效率降低、使系统的不同模块之间不容易协调等缺点,同时大大增加了系统的复杂度。所以在釆用迪米特法则时需要反复权衡,确保高内聚和低耦合的同时,保证系统的结构清晰。
二、模拟场景
通过模拟开发部经理、项目经理、员工之间的关系的例子来说明迪米特法则。
- 部门经理需要负责开发部各项目的运营情况;
- 项目经理需要负责一个项目的立项、开发、测试、运维、结算;
- 员工负责一个项目中某个模块的设计、开发、测试;
三、违背原则方案
1、程序员类
员工负责一个项目中某个模块的设计、开发、测试;有姓名、项目、模块、进度、计划完成时间属性。
package com.guor.beanutil.principle.dimit;
import lombok.Data;
@Data
public class Programmer {
// 姓名
private String name;
// 项目
private String project;
// 模块
private String module;
// 进度
private String schedule;
// 计划完成时间
private String completePlanTime;
public Programmer(String name, String project, String module, String schedule, String completePlanTime) {
this.name = name;
this.project = project;
this.module = module;
this.schedule = schedule;
this.completePlanTime = completePlanTime;
}
}
2、项目经理类
在项目经理类中初始化了项目人员信息,同时提供了简单的接口。
package com.guor.beanutil.principle.dimit;
import java.util.ArrayList;
import java.util.List;
public class ProjectManager {
// 姓名
private String name;
// 项目
private String project;
// 进度
private String schedule;
// 计划完成时间
private String completePlanTime;
// 项目开发人员
private static List<Programmer> programmerList;
static {
programmerList = new ArrayList<>();
programmerList.add(new Programmer(&#34;哪吒&#34;,&#34;哪吒闹海&#34;,&#34;技术选型,框架搭建&#34;,&#34;50%&#34;,&#34;2022-08-31&#34;));
programmerList.add(new Programmer(&#34;妲己&#34;,&#34;哪吒闹海&#34;,&#34;前端&#34;,&#34;30%&#34;,&#34;2022-08-31&#34;));
programmerList.add(new Programmer(&#34;敖丙&#34;,&#34;哪吒闹海&#34;,&#34;权限项目&#34;,&#34;20%&#34;,&#34;2022-08-31&#34;));
programmerList.add(new Programmer(&#34;申公豹&#34;,&#34;哪吒闹海&#34;,&#34;管理模块&#34;,&#34;20%&#34;,&#34;2022-08-31&#34;));
programmerList.add(new Programmer(&#34;二郎神&#34;,&#34;哪吒闹海&#34;,&#34;数据迁移&#34;,&#34;10%&#34;,&#34;2022-08-31&#34;));
}
public static List<Programmer> getProgrammerList(){
return programmerList;
}
}
3、开发部经理类
可以获取项目开发人员信息、开发进度、预计交付时间等。
类中通过Stream对代码进行了简化,我觉得Stream是java8新特性中最好用,也是最简洁的,有兴趣的可以体验一下【Java8 新特性 5】Java 8 stream的详细用法
package com.guor.beanutil.principle.dimit;
import java.util.*;
import java.util.stream.Collectors;
public class DepartmentManager {
/**
* 获取项目信息
*/
public static Map<String, Object> getProjectInfo(){
Map<String, Object> map = new HashMap<>();
String project = ProjectManager.getProgrammerList().get(0).getProject();
Double schedule = getSchedule3();
Date completePlanTime = getCompletePlanTime2();
map.put(&#34;项目&#34;,project);
map.put(&#34;项目进度&#34;,schedule);
map.put(&#34;预计完成时间&#34;,completePlanTime);
return map;
}
/**
* 项目列表
*/
public static List<String> getProjects(){
List<String> list = new ArrayList<>();
List<Programmer> programmerList = ProjectManager.getProgrammerList();
for (Programmer programmer : programmerList){
String project = programmer.getProject();
list.add(project);
}
return list;
}
/**
* 获取项目进度
* 写法1
*/
public static double getSchedule1(){
List<Programmer> programmerList = ProjectManager.getProgrammerList();
double sum = 0;
for (Programmer programmer : programmerList){
double schedule = programmer.getSchedule();
sum += schedule;
}
double avg = sum/programmerList.size();
return avg;
}
/**
* 获取项目进度
* 写法2
*/
public static Double getSchedule2(){
List<Programmer> programmerList = ProjectManager.getProgrammerList();
List<Double> scheduleList = new ArrayList<>();
for (Programmer programmer : programmerList){
scheduleList.add(programmer.getSchedule());
}
return scheduleList.stream().collect(Collectors.averagingDouble(Double::doubleValue));
}
/**
* 获取项目进度
* 写法3
*/
public static Double getAvgSchedule3(){
return ProjectManager.getProgrammerList().stream().mapToDouble( Programmer::getSchedule ).average().orElse(0d);
}
/**
* 项目预计完成时间
*
* 获取项目组内开发人员最晚完成时间即可
* 写法1
*/
public static Date getCompletePlanTime1(){
List<Programmer> programmerList = ProjectManager.getProgrammerList();
List<Date> dateList = new ArrayList<>();
for (Programmer programmer : programmerList){
dateList.add(programmer.getCompletePlanTime());
}
return dateList.stream().max(Date::compareTo).get();
}
/**
* 项目预计完成时间
*
* 获取项目组内开发人员最晚完成时间即可
* 写法2
*/
public static Date getCompletePlanTime2(){
return ProjectManager.getProgrammerList().stream().map(Programmer::getCompletePlanTime).max(Date::compareTo).get();
}
}
通过部门经理管理所有程序员,项目经理只提供了非常简单的信息,都是由部门经理类来操作,也就是说,一切事宜都是部门经理和程序员沟通,那,要项目经理干啥?部门经理管理10多个项目,上百号人,岂不是得累死...是的,你违反了迪米特法则~~
四、通过迪米特法则改善代码
部门经理直接调用项目经理类中的方法,获取项目名称,项目进展,预计完成时间等信息。 这样一来,整个功能逻辑就非常清晰了。
1、项目经理类
package com.guor.beanutil.principle.dimit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
public class ProjectManager {
// 姓名
private String name;
// 项目
private String project;
// 进度
private String schedule;
// 计划完成时间
private String completePlanTime;
// 项目开发人员
private static List<Programmer> programmerList;
static {
programmerList = new ArrayList<>();
programmerList.add(new Programmer(&#34;哪吒&#34;,&#34;哪吒闹海&#34;,&#34;技术选型,框架搭建&#34;,0.5,Programmer.getDate(&#34;2022-08-20&#34;)));
programmerList.add(new Programmer(&#34;妲己&#34;,&#34;哪吒闹海&#34;,&#34;前端&#34;,0.3,Programmer.getDate(&#34;2022-08-25&#34;)));
programmerList.add(new Programmer(&#34;敖丙&#34;,&#34;哪吒闹海&#34;,&#34;权限项目&#34;,0.2,Programmer.getDate(&#34;2022-08-31&#34;)));
programmerList.add(new Programmer(&#34;申公豹&#34;,&#34;哪吒闹海&#34;,&#34;管理模块&#34;,0.2,Programmer.getDate(&#34;2022-08-31&#34;)));
programmerList.add(new Programmer(&#34;二郎神&#34;,&#34;哪吒闹海&#34;,&#34;数据迁移&#34;,0.1,Programmer.getDate(&#34;2022-09-05&#34;)));
}
public static List<Programmer> getProgrammerList(){
return programmerList;
}
/**
* 项目列表
*/
public static List<String> getProjects(){
return ProjectManager.getProgrammerList().stream().map(Programmer::getProject).collect(Collectors.toList());
}
/**
* 获取项目进度
*/
public static Double getAvgSchedule(){
return ProjectManager.getProgrammerList().stream().mapToDouble( Programmer::getSchedule ).average().orElse(0d);
}
/**
* 项目预计完成时间
*
* 获取项目组内开发人员最晚完成时间即可
*/
public static Date getCompletePlanTime(){
return ProjectManager.getProgrammerList().stream().map(Programmer::getCompletePlanTime).max(Date::compareTo).get();
}
}
2、部门经理类
package com.guor.beanutil.principle.dimit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class DepartmentManager {
public static Map<String, Object> getProjectInfo(){
Map<String, Object> map = new HashMap<>();
String project = ProjectManager.getProjects().get(0);
Double schedule = ProjectManager.getAvgSchedule();
Date completePlanTime = ProjectManager.getCompletePlanTime();
map.put(&#34;项目&#34;,project);
map.put(&#34;项目进度&#34;,schedule);
map.put(&#34;预计完成时间&#34;,completePlanTime);
return map;
}
}
3、控制台输出
 |
|