1987年秋天由美国Northeastern University的Ian Holland提出,被UML的创始者之一Booch等普及。后来,因为在经典著作《 The Pragmatic Programmer》而广为人知。
也被称为最少知识原则(Least Knowledge Principle),是面向对象设计中的一条原则。它强调了类之间的低耦合和高内聚。根据迪米特法则,一个对象应该尽量减少与其他对象之间的交互,只与直接的朋友进行通信。这意味着在设计中,一个类应该尽可能少地依赖其他的类,而是通过与其他类的合作来实现某个功能。这样可以降低类之间的耦合度,使得代码更加灵活、可维护和可扩展。
对象对其他对象有限的了解:一个对象只应该与其直接朋友进行通信,不应该调用非直接朋友的方法。
不暴露对象的内部信息:一个对象不应该将自己的内部信息暴露给其他对象,而是通过提供公共接口来与其他对象进行交互。
最小化对象之间的交互:一个对象在设计时,应该尽量减少与其他对象之间的交互,只关注与自身相关的事务。
迪米特法则能够提高代码的可维护性和可复用性,减少代码的耦合度,同时也符合面向对象设计的封装思想。
一个对象应该对其他对象有限的了解,只与直接朋友进行通信。直接朋友包括以下几类:
该对象本身
以参数形式传入到该对象方法中的对象
该对象所创建的对象
该对象的成员变量引用的对象
根据迪米特法则,当我们设计一个对象时,应该尽量避免让该对象调用非直接朋友的方法。这样可以降低类之间的依赖关系,提高系统的可维护性和灵活性。
减少耦合度:通过限制对象之间的交互,可以减少类之间的依赖关系,使得系统更加松散耦合。
提高模块化:每个对象只和其直接朋友进行交互,使得每个模块的职责更加明确,易于理解和修改。
提升可维护性:减少了对象之间的依赖,修改一个对象不会对其它对象造成意外影响,从而减少了代码的风险。
尽量将逻辑封装在对象的内部,通过提供公共接口进行通信。
避免链式调用,尽量直接调用自身或成员变量引用的对象的方法。
少使用全局变量和单例模式,减少对象之间的全局状态共享。
使用依赖注入等技术来降低对象之间的耦合度。
老师让班长清点全班同学的人数。这个例子中总共有三个类:老师Teacher、班长GroupLeader和学生Student。
public interface ITeacher {
void command(IGroupLeader groupLeader);
}
public class Teacher implements ITeacher{
@Override
public void command(IGroupLeader groupLeader) {
// 全班同学
List<Student> allStudent = new ArrayList<>();
allStudent.add(new Student());
allStudent.add(new Student());
allStudent.add(new Student());
allStudent.add(new Student());
allStudent.add(new Student());
// 班长清点人数
groupLeader.count(allStudent);
}
}
**
* 班长类
*/
public interface IGroupLeader {
// 班长清点人数
void count(List<Student> students);
}
/**
* 班长类
*/
public class GroupLeader implements IGroupLeader{
/**
* 班长清点人数
* @param students
*/
@Override
public void count(List<Student> students) {
// 班长清点人数
System.out.println("上课的学生人数是: " + students.size());
}
}
/**
* 学生类
*/
public interface IStudent {
}
/**
* 学生类
*/
public class Student implements IStudent {
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
// 老师类
ITeacher wangTeacher = new Teacher();
// 班长
IGroupLeader zhangBanzhang = new GroupLeader();
wangTeacher.command(zhangBanzhang);
}
}
在这个例子中,我们的Teacher有几个朋友?两个,一个是GroupLeader,它是Teacher的command()方法的入参;另一个是Student,因为在Teacher的command()方法体中使用了Student
那么Teacher有几个是直接的朋友?按照直接的朋友的定义
只有GroupLeader是Teacher的直接的朋友。
Teacher在command()方法中创建了Student的数组,和非直接的朋友Student发生了交流,所以,上述例子违反了迪米特法则。方法是类的一个行为,类竟然不知道自己的行为与其他的类产生了依赖关系,这是不允许的,严重违反了迪米特法则!
public interface ITeacher {
void command(IGroupLeader groupLeader);
}
public class Teacher implements ITeacher {
@Override
public void command(IGroupLeader groupLeader) {
// 班长清点人数
groupLeader.count();
}
}
/**
* 班长类
*/
public interface IGroupLeader {
// 班长清点人数
void count();
}
/**
* 班长类
*/
public class GroupLeader implements IGroupLeader {
private List<Student> students;
public GroupLeader(List<Student> students) {
this.students = students;
}
/**
* 班长清点人数
*/
@Override
public void count() {
// 班长清点人数
System.out.println("上课的学生人数是: " + students.size());
}
}
/**
* 学生类
*/
public interface IStudent {
}
/**
* 学生类
*/
public class Student implements IStudent {
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
// 老师类
ITeacher wangTeacher = new Teacher();
List<Student> allStudent = new ArrayList(10);
allStudent.add(new Student());
allStudent.add(new Student());
allStudent.add(new Student());
allStudent.add(new Student());
// 班长
IGroupLeader zhangBanzhang = new GroupLeader(allStudent);
wangTeacher.command(zhangBanzhang);
}
}
这样修改后,每个类都只和直接的朋友交流,有效减少了类之间的耦合
一个人用咖啡机煮咖啡的过程,例子中只有两个类,一个是人,一个是咖啡机。
首先是咖啡机类CoffeeMachine,咖啡机制作咖啡只需要三个方法:1.加咖啡豆;2.加水;3.制作咖啡:
/**
* 咖啡机抽象接口
*/
public interface ICoffeeMachine {
//加咖啡豆
void addCoffeeBean();
//加水
void addWater();
//制作咖啡
void makeCoffee();
}
/**
* 咖啡机实现类
*/
public class CoffeeMachine implements ICoffeeMachine{
//加咖啡豆
public void addCoffeeBean() {
System.out.println("放咖啡豆");
}
//加水
public void addWater() {
System.out.println("加水");
}
//制作咖啡
public void makeCoffee() {
System.out.println("制作咖啡");
}
}
/**
* 人, 制作咖啡
*/
public interface IMan {
/**
* 制作咖啡
*/
void makeCoffee();
}
/**
* 人制作咖啡
*/
public class Man implements IMan {
private ICoffeeMachine coffeeMachine;
public Man(ICoffeeMachine coffeeMachine) {
this.coffeeMachine = coffeeMachine;
}
/**
* 制作咖啡
*/
public void makeCoffee() {
coffeeMachine.addWater();
coffeeMachine.addCoffeeBean();
coffeeMachine.makeCoffee();
}
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
ICoffeeMachine coffeeMachine = new CoffeeMachine();
IMan man = new Man(coffeeMachine);
man.makeCoffee();
}
}
在这个例子中,CoffeeMachine是Man的直接好友,但问题是Man对CoffeeMachine了解的太多了,其实人根本不关心咖啡机具体制作咖啡的过程。所以我们可以作如下优化:
优化后的咖啡机类,只暴露一个work方法,把制作咖啡的三个具体的方法
addCoffeeBean、addWater、makeCoffee设为私有:
/**
* 咖啡机抽象接口
*/
public interface ICoffeeMachine {
//咖啡机工作
void work();
}
/**
* 咖啡机实现类
*/
public class CoffeeMachine implements ICoffeeMachine {
//加咖啡豆
public void addCoffeeBean() {
System.out.println("放咖啡豆");
}
//加水
public void addWater() {
System.out.println("加水");
}
//制作咖啡
public void makeCoffee() {
System.out.println("制作咖啡");
}
@Override
public void work() {
addCoffeeBean();
addWater();
makeCoffee();
}
}
/**
* 人, 制作咖啡
*/
public interface IMan {
/**
* 制作咖啡
*/
void makeCoffee();
}
/**
* 人制作咖啡
*/
public class Man implements IMan {
private ICoffeeMachine coffeeMachine;
public Man(ICoffeeMachine coffeeMachine) {
this.coffeeMachine = coffeeMachine;
}
/**
* 制作咖啡
*/
public void makeCoffee() {
coffeeMachine.work();
}
}
/**
* 客户端
*/
public class Client {
public static void main(String[] args) {
ICoffeeMachine coffeeMachine = new CoffeeMachine();
IMan man = new Man(coffeeMachine);
man.makeCoffee();
}
}
这样修改后,通过减少CoffeeMachine对外暴露的方法,减少Man对CoffeeMachine的了解,从而降低了它们之间的耦合