跳到主要内容

迪米特法则

什么是迪米特法则

迪米特法则(Law of Demeter,简称 LoD)也称为最少知识原则(The Least Knowledge Principle),其核心思想是:

每个模块只应该了解那些与它关系密切的模块的有限知识。或者说,每个模块只和自己的朋友"说话",不和陌生人"说话"。

具体来说,迪米特法则包含两个核心要点:

  1. 不该有直接依赖关系的类之间,不要有依赖
  2. 有依赖关系的类之间,尽量只依赖必要的接口

如何实现"高内聚、松耦合"

迪米特法则的主要目标是实现代码的"高内聚、松耦合":

高内聚

  • 相近的功能应该放到同一个类中
  • 不相近的功能不要放到同一个类中
  • 功能修改时,修改点比较集中,容易维护

松耦合

  • 类与类之间的依赖关系简单清晰
  • 一个类的修改对其他类的影响较小
  • 修改时只需要考虑有限的依赖关系

代码示例

1. 违反迪米特法则的示例

// 网络传输类不应该直接依赖特定的请求类型
public class NetworkTransporter {
public byte[] send(HtmlRequest htmlRequest) {
String address = htmlRequest.getAddress();
byte[] data = htmlRequest.getContent().getBytes();
// 发送数据...
return null;
}
}

public class HtmlDownloader {
private NetworkTransporter transporter;

public Html downloadHtml(String url) {
HtmlRequest request = new HtmlRequest(url);
byte[] rawHtml = transporter.send(request);
return new Html(rawHtml);
}
}

2. 符合迪米特法则的重构

// 网络传输类只依赖通用的参数
public class NetworkTransporter {
public byte[] send(String address, byte[] data) {
// 发送数据...
return null;
}
}

public class HtmlDownloader {
private NetworkTransporter transporter;

public Html downloadHtml(String url) {
HtmlRequest request = new HtmlRequest(url);
byte[] rawHtml = transporter.send(
request.getAddress(),
request.getContent().getBytes()
);
return new Html(rawHtml);
}
}

3. 使用接口实现功能隔离

// 定义序列化接口
public interface Serializable {
String serialize(Object object);
}

// 定义反序列化接口
public interface Deserializable {
Object deserialize(String text);
}

// 实现类同时实现两个接口
public class Serialization implements Serializable, Deserializable {
@Override
public String serialize(Object object) {
// 序列化实现...
return null;
}

@Override
public Object deserialize(String text) {
// 反序列化实现...
return null;
}
}

// 客户端代码只依赖需要的接口
public class Client1 {
private Serializable serializer;

public Client1(Serializable serializer) {
this.serializer = serializer;
}
}

public class Client2 {
private Deserializable deserializer;

public Client2(Deserializable deserializer) {
this.deserializer = deserializer;
}
}

实践建议

  1. 合理划分类的职责

    • 避免类之间不必要的依赖
    • 保持类的功能单一和内聚
  2. 使用接口进行隔离

    • 通过接口定义有限的访问边界
    • 客户端只依赖必要的接口
  3. 注意依赖关系

    • 减少类之间的直接依赖
    • 使用依赖注入等方式管理依赖
  4. 平衡设计

    • 不要过度设计,导致代码过于复杂
    • 在实际应用中灵活把握原则

与其他原则的关系

迪米特法则与其他设计原则的关系:

  1. 单一职责原则

    • 都强调高内聚
    • 通过职责划分降低耦合
  2. 接口隔离原则

    • 都强调最小化依赖
    • 通过接口定义依赖边界
  3. 基于接口而非实现编程

    • 都强调降低耦合
    • 通过抽象隔离具体实现

总结

迪米特法则的核心是实现"高内聚、松耦合":

  1. 通过合理划分类的职责,实现高内聚
  2. 通过最小化依赖关系,实现松耦合
  3. 通过接口隔离,控制依赖范围
  4. 在实践中需要平衡,避免过度设计