2分钟通俗理解迪米特法则,架构设计筑基必看

来源:mikechen的互联网架构

迪米特法则是对软件实体之间通信的限制,它要求限制软件实体之间通信的宽度和深度。

迪米特法则提出,一个软件实体,应尽可能少的与其它实体交互。当一个模块修改时,就会尽量少对其他模块产生影响,系统扩展也会更加容易。

本文主要介绍迪米特法则,力求通过图文源码,一文彻底掌握它。

建议结合前几篇看,更容易融会贯通:

  1. 微信面试:说说里氏替换原则

  2. 精通接口隔离原则

  3. 依赖倒置原则就看这篇

  4. 3 分钟吃透开闭原则

  5. 单一职责原则让代码质量提升100倍


01
  什么是迪米特法则?

迪米特法则(LoD),又称为最少知识原则,英文全称 Least Knowledge Principle。

迪米特法则是指一个模块(类)只和与它高度相关的模块交流,尽量减少与其他模块(类)的直接交流。

大白话就是,模块之间的通信应该简单明了,每个模块只需要关心与它高度相关的模块,而不必了解整个系统的细节。

高度相关是指这些模块可能需要共同完成一项任务,或者相互依赖,以实现某个功能。

这有点像在现实生活中,你只与你的朋友直接交流,而不会与朋友的朋友(陌生人)交流。你的任何改变,都不会对朋友的朋友带来影响。


02
  迪米特法则的由来?

低耦合、高内聚是软件编程的总原则。

  • 耦合:指模块之间的联系程度。

  • 内聚:指模块内部元素的联系程度。

模块之间了解得越多,耦合就越紧。

任何一个模块的变化,都会影响到其他模块,系统就会变得很复杂。

无论是面向过程编程,还是面向对象编程,只有尽可能降低各个模块之间的耦合,才能提高代码的复用率。

低耦合的优点不言而喻,但是怎样才能实现低耦合呢?

这正是迪米特法则要去实现的。


03
  迪米特法则的核心思想?

迪米特法则的核心思想模块之间最少依赖。

  • 不该有直接依赖关系的类之间,就不要有依赖;


  • 有依赖关系的类之间,尽量只依赖必要的接口。

如果模块 A 需要与模块 B 交流,它应该直接与模块 B 通信,而不是通过模块 C、D、E ......

每个模块只与它高度相关的模块交流,减少了模块之间不必要的依赖。

使得每个模块都能更好地封装自己的功能,只暴露必要的接口,提高了模块的封装性和隔离性。


04
  迪米特法则的示例?

我们再来看具体示例,以便更好地理解迪米特法则及其应用。

假设:

公司要开发一款社交软件,需要研发用户发布帖子和发表评论的功能。

不遵循迪米特法则:

我们设计一个模块,让这个模块直接与用户、帖子和评论之间进行复杂的通信,以获取信息、创建帖子和评论。






















































// 用户模块class User {    String username;
   public User(String username) {        this.username = username;    }
   public void createPost(String content, Post post) {        // 用户创建帖子        post.setContent(content);    }
   public void addComment(String text, Post post) {        // 用户添加评论        Comment comment = new Comment(text);        post.addComment(comment);    }}
// 帖子模块class Post {    String content;    List comments = new ArrayList<>();
   public void setContent(String content) {        this.content = content;    }
   public void addComment(Comment comment) {        comments.add(comment);    }}
// 评论模块class Comment {    String text;
   public Comment(String text) {        this.text = text;    }}
public class SocialMediaApp {    public static void main(String[] args) {        User user1 = new User("Alice");        User user2 = new User("Bob");        Post post = new Post();
       user1.createPost("Hello, world!", post);        user2.addComment("Great post, Alice!", post);    }}

虽说这样也能实现需求,但弊端很明显。

用户模块直接与帖子模块、评论模块进行通信,用户模块需要知道帖子和评论的细节,包括它们的方法和属性,甚至需要直接访问它们的数据库。

模块之间的依赖关系很紧密,导致了紧耦合。

后续任何与用户、帖子或评论相关的变化,都会影响到这个模块,系统会很复杂 。


遵循迪米特法则:

现在,我们应用迪米特法则来改进这个设计。

按照迪米特法则,一个模块应该只与它的“朋友”通信。

在这种情况下,帖子可以被认为是用户的“朋友”,评论也可以被认为是帖子的“朋友”。

  • 用户模块只需要与帖子模块通信,以发布和管理帖子。


  • 帖子模块只需要与评论模块通信,以允许用户发表评论。


  • 用户模块和评论模块之间没有直接联系,它们不需要知道对方的全部细节。


















































class User {    String username;
   public User(String username) {        this.username = username;    }
   public void createPost(String content, Post post) {        post.setContent(content);    }
   public void addComment(String text, Post post) {        post.addComment(text);    }}
class Post {    String content;    List comments = new ArrayList<>();
   public void setContent(String content) {        this.content = content;    }
   public void addComment(String text) {        Comment comment = new Comment(text);        comments.add(comment);    }}
class Comment {    String text;
   public Comment(String text) {        this.text = text;    }}
public class SocialMediaApp {    public static void main(String[] args) {        User user1 = new User("Alice");        User user2 = new User("Bob");        Post post = new Post();
       user1.createPost("Hello, world!", post);        user2.addComment("Great post, Alice!", post);    }}

用户模块只与帖子模块交互,不直接与评论模块通信,它不需要知道评论的具体细节。

评论的具体实现对用户模块是透明的,用户只需要知道与帖子相关的操作。

如果我们要对用户模块进行修改,不会影响到评论模块,因为它们没有直接联系。

这种设计减少了模块之间的依赖关系,系统更加灵活、容易扩展。


总结
  

迪米特法则的核心思想是:不该有直接依赖关系的类之间,就不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口

迪米特法则避免与非直接的类通信,使模块与模块之间保持较低的耦合关系。

但是,要通信,必然就要通过“中介”来联系。过分使用迪米特原则,系统中就会存在大量“中介”,这在一定程度上增加了系统的复杂度。

应用时需要综合权衡,既要做到结构清晰,又要实现高内聚、低耦合。

建议收藏备用,架构设计筑基必知必会,大厂面试也爱问。

请使用浏览器的分享功能分享到微信等