迪米特法则也叫做最少知道原则。
附链
你也可以在这些平台阅读本文:
定义
一个对象应该对其他对象保持最少的了解。
在《Head First 设计模式》一书中,针对该原则也强调:只和你的密友交流。
在程序中,出现在成员变量、方法的输入、输出参数中的类我们可以称之为成员朋友类,而出现在方法体内部的类不属于朋友类。
这些个成员朋友类的对象和当前对象之间存在关联、聚合或者组合关系,可以直接访问这些成员朋友类对象的方法。
场景示例
假设现在超市老板来超市向职工说要看看目前超市内的商品总数量。
这里会牵扯到几个实体类:老板类、职工类、商品类。
创建商品类
/**
* @author zhh
* @description 商品类
* @date 2020-02-07 11:00
*/
public class Goods {
}
创建职工类
在职工类的内部实现一个职工查询商品数量的方法。
/**
* @author zhh
* @description 职工类
* @date 2020-02-07 11:02
*/
public class Staff {
/**
* 职工查询商品数量
* @param goods 商品列表
*/
public void checkNumber(List<Goods> goods) {
System.out.println("目前超市内商品总数为: " + goods.size());
}
}
创建老板类
在老板类的内部实现老板要求职工查询商品数量的方法。
/**
* @author zhh
* @description 老板类
* @date 2020-02-07 10:59
*/
public class Boss {
/**
* 老板要求职工查商品的数量
* @param staff 职工
*/
public void requireCheckNumber(Staff staff) {
List<Goods> goodsList = new ArrayList<Goods>();
// 这里模拟从数据库查商品数量
for (int i = 0; i < 50; i++) {
goodsList.add(new Goods());
}
staff.checkNumber(goodsList);
}
}
测试类及输出
/**
* @author zhh
* @description 测试类
* @date 2020-02-07 11:09
*/
public class Test {
public static void main(String[] args) {
Boss boss = new Boss();
Staff staff = new Staff();
boss.requireCheckNumber(staff);
}
}
测试类的输出结果如下:
目前超市内商品总数为: 50
类结构图
以上示例类的结构图如下所示
问题所在
前面提到过,迪米特法则强调只和密友交流。
在 Boss
类当中, Staff
作为方法的入参可以作为直接的朋友类。而 Goods
是出现在方法体内部的类,并不属于朋友类。
Boss
直接要求 Staff
查询商品的总数量,只需要将结果告知即可。 Boss
并不需要关注 Goods
这个类。
方案调整
调整老板类
public class Boss {
/**
* 老板要求职工查商品的数量
* @param staff 职工
*/
public void requireCheckNumber(Staff staff) {
staff.checkNumber();
}
}
调整职工类
public class Staff {
/**
* 职工查询商品数量
*/
public void checkNumber() {
List<Goods> goodsList = new ArrayList<Goods>();
// 这里模拟从数据库查商品数量
for (int i = 0; i < 50; i++) {
goodsList.add(new Goods());
}
System.out.println("目前超市内商品总数为: " + goodsList.size());
}
}
类结构图
调整后的整体类结构图如下
通过前后对比类图,我们不难发现,调整后的类结构中 Boss
类和 Goods
类没有直接的关联关系。
优点
- 降低类之间的耦合,提高模块的相对独立性。
- 提高类的可复用性和系统的扩展性。
缺点
过度使用迪米特法则会使系统产生大量中介类,从而增加系统的复杂性,使模块之间的通信效率降低。
总结
迪米特法则主要强调以下两点:
- 从依赖者的角度来说,只依赖应该依赖的对象。
- 从被依赖者的角度说,只暴露应该暴露的方法。
注意点
- 在类的划分上,应创建弱耦合的类。类与类之间的耦合越弱,就越有利于实现可复用的目标。
- 在类的结构设计上,尽量降低类成员的访问权限。
- 在类的设计上,优先考虑将一个类设置成不变类。
- 在对其他类的引用上,将引用其他对象的次数降到最低。
- 不暴露类的属性成员,而应该提供相应的 get 和 set 方法。
- 谨慎使用序列化 (Serializable) 功能。
参考
- 《Head First 设计模式》
- 《大话设计模式》