设计模式-迪米特法则

news2024/9/21 10:38:17

代码世界中类间的耦合关系会直接影响代码可复用性、可读性、可扩展性等。这种耦合关系就如同人之间朋友关系一样,志不同道不合不应相于谋,否则最终只会落得个互相伤害的下场。代码组织时也应如此,应按照一定的原则处理好类之间的关系,否则就会导致恶性耦合只会使得项目代码越写越烂,难以维护。这个原则就是迪米特原则。

一、迪米特原则概念

迪米特法则(Law of Demeter, LOD),也称之为最少知识原则,指的一个类应该对自己需要耦合或调用的类知道的最少。相应一些英文定义:

  • Each unit should have only limited knowledge about other units: only units “closely” related to the current unit.
    (每个单元对于其他的单元只能拥有有限的知识:只是与当前单元紧密联系的单元)
  • Each unit should only talk to its friends; don’t talk to strangers. (每个单元只能和它的朋友交谈:不能和陌生单元交谈)
  • Only talk to your immediate friends. (只和自己直接的朋友交谈) (来自维基百科)

不论是中文定义还是英文定义,我想根据自己的理解换一种说法,即“一个类应该与自己应该依赖的类产生依赖,而不应该与自己不该依赖的类产生依赖”。这样的说法似乎更容易被理解一些,那继而来的问题就是,哪些是这个类应该依赖的?哪些是不应该以来的呢?这些应该依赖的类在英文定义中称之为"朋友类"。
在“朋友类”的定义和判断上,一些参考资料给出的是出现在类成员变量、类方法的输入输出参数中的类称为朋友类,而出现在方法体内部的类不属于朋友类。个人对这个定义不是很赞同,这个定义可以用来评价现有代码是否符合迪米特原则时判断朋友类,但是不适用代码设计阶段。即,我们在设计代码时,哪些类应该是朋友类这个定义不能很好的给我们回答。我个人认为,在单一职责原则基础上,应该强耦合的朋友类之间所对应的业务逻辑也是强耦合的。所有原则、代码设计均是以业务逻辑为基础,只要这样才能更好的服务于业务。所以,判断类之间是否为朋友类,就看类所负责的业务之间是否强耦合,对于非强耦合业务类不要产生依赖,这也满足了类对自己调用的类知道的最少【业务都强耦合,代码类上必须依赖呀,没法子不依赖哈】。
举个栗子,在RPC服务中大概可以有接口层、业务层、数据层等,根据业务逻辑的耦合关系来看,接口层会依赖业务层提供业务能力,返回业务数据,但是不能够依赖数据层直接获取存储数据,这就不满足迪米特原则了。再举一个其他资料的案例,公司类(Company)应该仅依赖部门(Department),不应该直接依赖员工(Employee)。另外,我们常熟知的DO、BO、DTO等这种分层规范也是应用迪米特原则的一种体现。

二、应用实践

前面已经基本说清楚迪米特法则的基本概念了,这个章节将通过一个非常简单的案例演示下迪米特法则的应用。我们平常在零碎的时间里,喜欢看一些书籍,一般都是电子书,现在我们看书的操作是这样的:唤醒手机,打开阅读软件,选择书籍,然后阅读。总共 3 个步骤,涉及了 3 样东西:手机、软件、书籍。现在使用代码来描述下这个过程。

2.1 未应用迪米特法则

在未应用迪米特法则时,我们可能会写出下面这样的代码:
① 书籍

public class Book {
    private String title;

    public Book(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

② 软件应用

public class App {
    public void read(Book book) {
        System.out.println(book.getTitle());
    }
}

③ Phone

public class Phone {
    App app = new App();
    Book book = new Book("设计模式");
    public void readBook() {
        app.read(book);
    }
}

④ 客户端

public class Client {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.readBook();
    }
}

在这里插入图片描述
从类图上来看,首先电子书应用是由电子书籍构成,因此APP与Book的关系不应该是依赖关系,更应该是强依赖的组合关系。再者,手机和电子书之前不应该存在耦合(依赖)关系,没有电子书,手机一样能够作为他用。如果在之后的业务逻辑中,如果书籍业务扩增,如添加类型、版权等都会影响到本不该影响的手机Phone业务。由此可以看出,Phone依赖了不该依赖的类Book,这种依赖业务的变化十分不可控,对依赖方的影响也不可控,继而导致系统稳定性、可扩展性降低。

2.2 应用迪米特法则

基于以上问题,如果应用迪米特法则,那么Phone类应该就只能够依赖App类,而App类也只依赖Book类。代码修改如下:
① 书籍
书籍和$2.1节相同,不重复补充。
② 软件应用

public class App {
    private Book book;

    public App(Book book) {
        this.book = book;
    }

    public void read() {
        System.out.println(book.getTitle());
    }
}

③ Phone

public class Phone {
    private App app;

    public Phone(App app ) {
        this.app = app;
    }

    public void readBook() {
        app.read();
    }
}

④ 客户端

public class Client {
    public static void main(String[] args) {
        App app = new App(new Book("设计模式"));
        Phone phone = new Phone(app);
        phone.readBook();
    }
}

在这里插入图片描述
这样的代码类耦合关系看起来就十分舒服了,书籍相关业务变动只可能会影响其和App之间的关系,即便重构也不会影响到Phone相关业务,明显提高了代码稳定性和扩展性。
这里可能有人会有疑问,前后两个方案对比,那Client类不是依赖的更多了吗?本来只需要依赖一个Phone类,然而改造后依赖了三个类。没错,确实Client依赖更多,但是这是符合业务逻辑的,“唤醒手机,打开阅读软件,选择书籍”,作为执行者执行这一套动作,肯定需要知道什么书籍(Book具体对象),什么应用(App对象),什么手机(Phone对象),因此这种依赖是符合业务逻辑的。此外,之前文章中也说过,Client不属于设计模式考虑范围之内,Client中是处理类对象行为过程,非代码设计讨论范围之内的。

【参考资料】

  • 迪米特法则-知乎【推荐理由:符合作者个人理解】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/733407.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++常用库函数 3.数据转换函数

函数名&#xff1a;abs 函数原型&#xff1a;int abs(int n)&#xff1b; 参数&#xff1a;n 整数值。 所需头文件&#xff1a;<cstdlib> 功能&#xff1a;求绝对值。 返回值&#xff1a;返回 n 的绝对值。函数名&#xff1a;atof&#xff0c;atoi&#xff0c;atol …

第42节:cesium 火焰效果(含源码+视频)

结果示例: 完整源码: <template><div class="viewer"><!-- :shouldAnimate="true" 添加动画 --><vc-viewer @ready

linux 命令之find

find 命令 1. 作用 命令用于在指定目录下以及其子母路查找文件和目录。 2. 语法 find [path] [expression] 不指定path的默认为当前路径 2.1 常见的参数 -name pattern&#xff1a;按文件名查找&#xff0c;支持使用通配符 * 和 ?。 -type type&#xff1a;按文件类型查…

NVIC的中断挂起寄存器和EXTI的中断挂起寄存器的区别

&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;仅个人拙见&#xff0c;若有错误&#xff0c;欢迎大家指正&#xff0…

Spring MVC 程序开发

什么是 Spring MVC&#xff1f; 官⽅对于 Spring MVC 的描述是这样的&#xff1a; Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, “Spring Web MVC,”…

数据特征降维 | 核主元分析KPCA数据降维

文章目录 效果一览文章概述部分源码部分源码参考资料效果一览 文章概述 数据特征降维 | 核主元分析KPCA,主要用于数据降维。 部分源码 部分源码 %% 清空环境变量 warning off % 关闭报警信息 close all % 关闭开启的图窗 clear …

SpringBoot(六)SpringBoot项目部署到腾讯云服务器

这篇文章&#xff0c;可以说是干货满满。关注我的同学应该直到&#xff0c;之前我有几篇SpringBoot的文章&#xff0c;介绍了如何搭建本地服务器&#xff08;没看过的同学可以系统地看下我的SpringBoot专栏&#xff0c;保证你会有很多的收获&#xff09;。但我们那都是在本地玩…

CSDN1周年的创作纪念日【个人总结】

机缘 2022年的7月&#xff0c;第一次了解到这个平台。 得知这个平台可以实现以下功能&#xff1a; 例如&#xff1a; 实战项目中的经验分享日常学习过程中的记录通过文章进行技术交流… 收获 其实出发点是我自己整合笔记&#xff0c;顺带佛系分享给大家看&#xff0c;但是好…

在原有J-IM基础上改造,开发记录方便日后学习,主要区别加入mysql持久化,但是不完善、仅供参考

在原有J-IM基础上改造&#xff0c;开发记录方便日后学习&#xff0c;主要区别加入mysql持久化&#xff0c;但是不完善、仅供参考 原站地址 https://gitee.com/xchao/j-im 改造后的地址 https://gitee.com/lbx_1397372495/jim-chat 本地启动测试 1&#xff0c;修改mysql 数…

Windows 安装 RabbitMq 和 Erlang

1.安装Erlang 音乐RabbitMq是基于Erlang开发的&#xff0c;所以先要安装这个环境 下载地址&#xff1a;32位 64位 其他版本自己找 官网 下载完之后无脑安装直接一直下一步 2.配置Erlang环境变量 2.1 新建ERLANG_HOME 把自己的安装的根目录填进去 比如&#xff1a;C:\Progra…

计算机体系结构基础知识介绍之缓存性能的十大进阶优化之小型且简单的一级缓存(二)

缓存是一种高速的存储器&#xff0c;用于存放处理器经常访问的数据和指令。缓存的组织方式有多种&#xff0c;其中一种是按照不同的关联度(associativity)来划分。关联度表示一个缓存块(block)可以放在缓存中的位置数。关联度越高&#xff0c;缓存中可以容纳的不同块的数量越多…

动态规划之62 不同路径(第4道)

题目&#xff1a; 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。 问总共有多少条不同的路径&…

网络的构成要素【图解TCP/IP(笔记七)】

文章目录 网络的构成要素通信媒介与数据链路网卡中继器网桥/2层交换机路由器/3层交换机4&#xff5e;7层交换机网关各种设备及其对应网络分层概览 网络的构成要素 通信媒介与数据链路 计算机之间通过电缆相互连接。电缆可以分为很多种&#xff0c;包括双绞线电缆、光纤电缆、同…

Vue3.3 编译宏

Vue 3.3新增了一些语法糖和宏&#xff0c;包括泛型组件、defineSlots、defineEmits、defineOptions defineProps 父子组件传参 <template><div><Child name"xiaoman"></Child></div> </template><script langts setup>…

简要介绍 | 两阶段点云目标检测:理论与实践

注1&#xff1a;本文系“简要介绍”系列之一&#xff0c;仅从概念上对两阶段点云目标检测进行非常简要的介绍&#xff0c;不适合用于深入和详细的了解。 两阶段点云目标检测&#xff1a;理论与实践 在这篇博客中&#xff0c;我们将探索两阶段点云目标检测的理论基础和实际应用…

【朱颜不曾改,芳菲万户香。AIGC人物图片创作---InsCode Stable Diffusion 美图活动一期】

【朱颜不曾改&#xff0c;芳菲万户香。AIGC人物图片创作 ---InsCode Stable Diffusion 美图活动一期】 本文目录&#xff1a; 一、 Stable Diffusion 模型在线使用 1.1、模板运行环境配置 1.2、运行InsCode平台的Stable Diffusion模板 二、Stable Diffusion主界面功能 2.…

【5G PHY】5G控制资源集CORESET介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

OpenCV 的安装与配置指南(Windows环境,Python语言)

OpenCV 的安装与配置指南&#xff08;Windows环境&#xff0c;Python语言&#xff09; 导语一、安装 Python 二、安装 OpenCV 库三、配置 OpenCV 环境变量四、验证 OpenCV 安装总结 导语 OpenCV 是一个功能强大的计算机视觉库&#xff0c;广泛应用于图像处理和计算机视觉领域。…

解决IDEA/WebStorm的Ctrl+Shift+F冲突失效

IDEA 的 CtrlShiftF 是全文或全项目搜索搜索快捷键&#xff0c;非常好用。 当这个快捷键偶而会失效时&#xff0c;基本可以确定是快捷键冲突了。 检查所有运行的软件的快捷键&#xff0c;若有设置为CtrlShiftF的则改掉。特别是输入法会占用较多的快捷键。 例如我这里的搜过输…

MySQL表单查询

根据题目完成下列要求 CREATE TABLE emp ( empno int(4) NOT NULL, ename varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, job varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, mgr int(4) NULL DEFAULT …