携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情
简介
迪米特原则软件行业内的含义是如果两个软件实体(模块,类,方法)不需要直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性,避免在修改一个软件实体时影响到它的调用方。说白了终极目的还是高内聚、低耦合的思想。
那我理解用一句话概括:尽量少和陌生人说话!
那问题来了,哪些是陌生人,同事算吗?邻居算吗?隔壁班的妹纸算吗?且听我一一道来。
朋友:出现在成员变量,方法输入,输出参数中的类称为成员朋友类。
陌生人:局部变量中的类则不是直接的朋友。
这样看来也是比较好理解的,成员变量、输入、输出都是朋友,而且这些朋友往往是出现在比较醒目的位置:成员变量经常在类的头部定义,而输入输出也是在方法的一头一尾定义,即使有改动也是非常容易找到的。相反在一个方法中的局部变量是比较难找的,因为方法的每一行都可能定义。
应用
就拿我们最熟悉的用户角色权限来举例子:
public class User {
/**
* 同过用户id查询其拥有的角色
* @return
*/
public List<Permission> getPermisionListByUser(Integer userId) {
Role role = new Role();
Integer roleId = role.getRoleIdByUserId(userId);
Permission permissionService = new Permission();
return permissionService.getPermissionListByRole(roleId);
}
}
public class Role {
public Integer getRoleIdByUserId(Integer userId) {
return Integer.MAX_VALUE;
}
}
public class Permission {
/**
* 通过角色Id查询此角色的权限
* @param roleId
* @return
*/
public List<Permission> getPermissionListByRole(Integer roleId) {
ArrayList<Permission> permList = new ArrayList<>();
permList.add(new Permission());
return permList;
}
}
以上3个类实现了通过用户id查询用于所有的权限。通过在UserService中的getPermisionListByUser实现了此功能。没毛病,但是违反了迪米特原则,因为在此方法中出现了RoleService和PermissionService这2个陌生人。
下面我们开始改造,干掉陌生人的出现。
public class User {
/**
* 同过用户id查询其拥有的角色
* @return
*/
public List<Permission> getPermisionListByUser(Integer userId, Role role) {
return role.getPermissionListByUserId(userId);
}
}
public class Role {
public List<Permission> getPermissionListByUserId(Integer userId) {
ArrayList<Permission> permList = new ArrayList<>();
permList.add(new Permission());
return permList;
}
}
public class Permission {
}
如此,完美遵循迪米特原则。
总结
我觉得迪米特法则不是一定要按照原则强制执行的,在实际开发中不可能不引入其他类型的局部变量,但是咱们要尽可能地少用,不是不和陌生人说话,而是要尽量少说。
1、在类功能的划分上应该尽可能地减少耦合,功能分离,他们之间的耦合越小,越利于实现可复用
2、迪米特法则的要求其实对代码整洁也是很有帮助的,少引入局部变量肯定就要求代码有更多更好的封装。方法的长度也能得到有效控制
3、不暴露类的属性成员,而应该提供相应的访问器(get、set)
4、在类的结构设计上,尽量降低类成员的访问权限