设计原则之【迪米特法则】,非礼勿近

news2025/3/11 3:06:10

文章目录

  • 一、什么是迪米特法则
    • 1、理解迪米特法则
    • 2、如何理解“高内聚、松耦合”?
  • 二、实例
    • 1、实例1
    • 2、实例2

一、什么是迪米特法则

迪米特原则(Law of Demeter LoD)是指一个对象应该对其他对象保持最少的了解,又叫最少知道原则(Least Knowledge Principle,LKP),尽量降低类与类之间的耦合。迪米特原则主要强调只和朋友交流,不和陌生人说话。出现在成员变量、方法的输入、输出参数中的类都可以称之为成员朋友类,而出现在方法体内部的类不属于朋友类。

其含义是:如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的是降低类之间的耦合度,提高模块的相对独立性。

迪米特法则中的“朋友”是指:当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,这些对象同当前对象存在关联、聚合或组合关系,可以直接访问这些对象的方法。

1、理解迪米特法则

不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。迪米特法则是希望减少类之间的耦合,让类越独立越好。每个类都应该少了解系统的其他部分。一旦发生变化,需要了解这一变化的类就会比较少。

2、如何理解“高内聚、松耦合”?

“高内聚、松耦合”是一个非常重要的设计思想,能够有效提高代码的可读性和可维护性,缩小功能改动导致的代码改动范围。“高内聚”用来指导类本身的设计,“松耦合”用来指导类与类之间依赖关系的设计。

所谓高内聚,就是指相近的功能应该放到同一个类中,不相近的功能不要放到同一类中。相近的功能往往会被同时修改,放到同一个类中,修改会比较集中。所谓松耦合指的是,在代码中,类与类之间的依赖关系简单清晰。即使两个类有依赖关系,一个类的代码改动也不会或者很少导致依赖类的代码改动。

二、实例

1、实例1

现在来设计一个权限系统,TeamLeader需要查看目前发布到线上的课程数量。这时候,TeamLeader要找到员工 Employee 去进行统计,Employee 再把统计结果告诉 TeamLeader。接下来我们还是来看代码:

public class Course {
}

public class Employee{
	public void checkNumberOfCourses(List<Course> courseList){
		System.out.println("目前已发布的课程数量是:" + courseList.size());
	}
}

public class TeamLeader{
	public void commandCheckNumber(Employee employee){
		List<Course> courseList = new ArrayList<Course>();
		for (int i= 0; i < 20 ;i ++){
			courseList.add(new Course());
		}
		employee.checkNumberOfCourses(courseList);
	}
}

public static void main(String[] args) {
	TeamLeader teamLeader = new TeamLeader();
	Employee employee = new Employee();
	teamLeader.commandCheckNumber(employee);
}

写到这里,其实功能已经都已经实现,代码看上去也没什么问题。根据迪米特原则,TeamLeader只想要结果,不需要跟 Course 产生直接的交流。而 Employee 统计需要引用 Course 对象。TeamLeader和 Course 并不是朋友,从下面的类图就可以看出来:
在这里插入图片描述
下面来对代码进行改造:

public class Employee {
	public void checkNumberOfCourses(){
		List<Course> courseList = new ArrayList<Course>();
		for (int i= 0; i < 20 ;i ++){
			courseList.add(new Course());
		}
		System.out.println("目前已发布的课程数量是:"+courseList.size());
	}
}

public class TeamLeader {
	public void commandCheckNumber(Employee employee){
		employee.checkNumberOfCourses();
	}
}

再来看下面的类图,Course 和 TeamLeader 已经没有关联了。
在这里插入图片描述
迪米特法则的核心是降低类之间的耦合。
但是要注意:由于每个类都减少了不必要的依赖,因此迪米特法则只是要求降低类间(对象间)耦合关系,并不是要求完全没有依赖关系。

2、实例2

我们实现一个简化版的搜索引擎爬取网页的功能。代码中包含三个主要的类。其中,NetUtil 类负责底层网络通信,根据请求获取数据;HtmlDownloader 类用来通过 URL 获取网页;Document 表示网页文档,后续的网页内容抽取、分词、索引都是以此为处理对象。

public class NetUtil{
    // 省略属性和其他方法...
    public Byte[] send(HtmlRequest htmlRequest) {
      //...
    }
}
public class HtmlDownloader {
  private NetUtil netUtil;//通过构造函数或IOC注入
  
  public Html downloadHtml(String url) {
    Byte[] rawHtml = netUtil.send(new HtmlRequest(url));
    return new Html(rawHtml);
  }
}
public class Document {
  private Html html;
  private String url;
  
  public Document(String url) {
    this.url = url;
    HtmlDownloader downloader = new HtmlDownloader();
    this.html = downloader.downloadHtml(url);
  }
  //...
}

我们分析一下这三个类,虽然看起来没什么问题,但是仍有优化的空间。

首先看NetUtil类,作为一个工具类,应该尽可能的“通用”,send方法不应该依赖HtmlRequest 。

public class NetUtil {
    // 省略属性和其他方法...
    public Byte[] send(String address, Byte[] data) {
      //...
    }
}

我们修改了NetUtil 类,那么HtmlDownloader 也应该同步修改:

public class HtmlDownloader {
  private NetUtil netUtil;//通过构造函数或IOC注入
  
  public Html downloadHtml(String url) {
  	HtmlRequest htmlRequest = new HtmlRequest(url);
    Byte[] rawHtml = netUtil.send(htmlRequest.getAddress(), htmlRequest.getContent().getBytes());
    return new Html(rawHtml);
  }
}

Document类构造方法中downloadHtml耗时较长,不应该放在构造方法中,影响代码的可测试性;
HtmlDownloader 对象在构造函数中通过 new 来创建,违反了基于接口而非实现编程的设计思想,也会影响到代码的可测试性;
从业务含义上来讲,Document 网页文档没必要依赖 HtmlDownloader 类,违背了迪米特法则。

ublic class Document {
  private Html html;
  private String url;
  
  public Document(String url, Html html) {
    this.html = html;
    this.url = url;
  }
  //...
}
// 通过一个工厂方法来创建Document
public class DocumentFactory {
  private HtmlDownloader downloader;
  
  public DocumentFactory(HtmlDownloader downloader) {
    this.downloader = downloader;
  }
  
  public Document createDocument(String url) {
    Html html = downloader.downloadHtml(url);
    return new Document(url, html);
  }
}

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

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

相关文章

支付系统设计三:渠道网关设计01-总览

文章目录 前言一、开发框架二、E-R图三、管理后台配置四、运行时执行流程五、屏蔽渠道差异总结 前言 在《支付系统设计一&#xff1a;支付系统产品化》文章中&#xff0c;我们知道支付渠道网关主要具有以下功能&#xff1a; 统一支付出口&#xff0c;提供丰富的支付工具原子能…

详解:扫雷游戏的实现

扫雷游戏的实现 设置雷排查雷标记雷打印棋盘初始化棋盘获得雷的个数扩展区域test.c的实现meni.c的实现meni.h的实现 铁汁们&#xff0c;今天给大家分享一篇扫雷游戏的实现&#xff0c;来吧&#xff0c;开造⛳️ 1.需要存储雷的信息&#xff0c;创建二维数组来存储数据信息&…

gateway的使用

什么是Spring Cloud Gateway 网关作为流量的入口&#xff0c;常用的功能包括路由转发&#xff0c;权限校验&#xff0c;限流等。 Spring Cloud Gateway 是Spring Cloud官方推出的第二代网关框架&#xff0c;定位于取代 Netflix Zuul。相比 Zuul 来说&#xff0c;Spring Cloud …

第1章 量化设计与分析基础

1.1 引言 如今一台价格不足500美元的手机&#xff0c;性能便堪比1993年世界上最快的售价5000万美元的计算机&#xff0c;这种快速发展既得益于计算机制造技术的发展&#xff0c;也得益于计算机设计的创新。 纵观计算机发展的历史&#xff0c;技术一直在稳定地提升&#xff0c…

【COT】Chain-of-Thought Prompting Elicits Reasoning in Large Language Models

文章目录 主要解决什么问题采用什么方法实验分析与结果消融实验Commonsense ReasoningSymbolic Reasoning 问题与展望 Chain-of-Thought Prompting Elicits Reasoning in Large Language Models 主要解决什么问题 大语言模型越来越大&#xff0c;效果越来越好。但是在一些具有…

Sui Builder House首尔站|主网上线后首次亮相

Sui Builder House提供与全球Sui构建者会面、合作并学习Sui平台前沿技术的机会。Sui基金会计划将于2023年在全球12个城市举办Sui Builder House。截止目前&#xff0c;已成功在美国丹佛市、越南胡志明市和中国香港举办三场Builder House活动。 Sui Builder House首尔站将于6月…

【D435i深度相机YOLO V5结合实现目标检测】

【D435i深度相机YOLO V5结合实现目标检测】 1. 前言2 分析2.1 关于yolo部分2.2 关于获取三维坐标的部分2.3 关于文件结构部分 3. 代码 1. 前言 参考&#xff1a;Ubutntu下使用realsense d435i&#xff08;三&#xff09;&#xff1a;使用yolo v5测量目标物中心点三维坐标 欢迎大…

满意度指标- NPS 的ABtest(公式推导)

&#x1f449;A 组的NPS如下 &#x1f449;B 组的NPS如下 &#xff08;下标为1&#xff0c;均为A组的样本数据&#xff1b;下标为2&#xff0c;均为B组的样本数据&#xff09; 要验证A\B两组的NPS差异是否显著&#xff0c;可通过假设检验。 一、假设检验前置准备 1. 选择…

FastDFS理论与Java程序的对接(图片,文件上传)

目录 fastdfs概述Java程序对接fastDFSpom配置java启动类注解yaml文件配置controller类service类 fastdfs概述 什么是分布式文件系统&#xff1f; 是指文件系统管理的物理存储资源不一定直接连接在本地节点上&#xff0c;而是通过计算机与节点相连。 通俗来讲&#xff1a; 传统…

【medini analyze 软件介绍】

medini analyze 软件介绍 简介主要功能&#xff08;功能安全范畴&#xff09;1、HARA2、建模3、FMEA & FMEDA4、FTA*这里只是笔者根据汽车功能安全分析经验简单列举了medini analyze的部分功能&#xff0c;完整的功能介绍请参考ANSYS官网* 简介 medini analyze是一款专业的…

怎么把pdf文件压缩到最小?四招快速压缩!

怎么把pdf文件压缩到最小&#xff1f;平常我们要压缩一个文件&#xff0c;一般都知道该如何操作。系统中自带了压缩工具&#xff0c;只需右键点击需要压缩的对象并选择"压缩"选项即可完成操作。然而&#xff0c;很多人也会发现&#xff0c;尽管大部分的文件都可以通过…

网络安全公司Dragos披露网络安全事件

工业网络安全公司 Dragos 披露了它所称的“网络安全事件”&#xff0c;此前一个已知的网络犯罪团伙试图突破其防御并渗透到内部网络以加密设备。 虽然 Dragos 表示威胁行为者没有破坏其网络或网络安全平台&#xff0c;但他们可以访问公司的 SharePoint 云服务和合同管理系统。…

05-HTML-图片标签

<img> 标签&#xff1a;src 属性是必需的。它规定图像的 URL。 绝对 URL - 指向另一个网站&#xff08;比如 src"http://www.example.com/image.gif"&#xff09;相对 URL - 指向网站内的一个文件&#xff08;比如 src"image.gif"&#xff09; <…

网络层最重要的协议—IP协议

网络层最重要的协议—IP协议 IP协议格式解决IP地址不够用问题的三种方法方法一: 动态分配IP地址方法二: NAT网络地址转换方法三: IPv6(根本上解决IP不够用的问题)小结&#xff1a; IP协议之地址管理主机号/网络号子网掩码特殊IP IP协议格式 4位版本&#xff1a;此处取4或64位首…

sort ,uniq ,tr ,cut命令

目录 一、sort命令 1.格式 2.命令演示 2.1 选项 -n :按照数字大小排序 2.2选项 -r &#xff1a;反向排序 2.3选项 -u&#xff1a;隐藏多余行 2.4选项 -t &#xff1a;指定分隔符&#xff1b;-k &#xff1a;指定字符&#xff1b;-o &#xff1a;指定保存文件 二、uniq命令…

Git的安装与版本控制

这里写目录标题 原理安装基本使用gitee-IDEA协同开发成员邀请开发组成员指定仓库权限给当前仓库设定分支提交代码时必须向自己的分支提交合并分支 - 无冲突 原理 Git本地有四个工作区域&#xff1a; 工作目录&#xff08;Working Directory&#xff09;、暂存区(Stage/Index)、…

【Linux】笔记分享

目录 - 前言- 目录结构- 磁盘文件系统- 文件权限 ls -l 的内容文件及目录权限实际案例 修改权限 -chmod[change ...]第一种方式&#xff1a; 、-、 变更权限第二种方式&#xff1a;通过数字变更权限 修改文件所有者 -chown 修改文件所在组 -chgrp - 命令类型基础命令网络性能…

【数据类型-列表】------- PYTHON基础9

内容目录 一、数据类型-列表1. 列表1.1. 列表的截取 result List[start:end:step]1.2. 列表元素的修改 List[index] element1.3. 列表元素的删除 del List[index] 或 del List[start:end:step]1.4. 列表元素的拼接 “” 或者增量赋值运算符 “” 2. 列表常用内置函数 对象.内…

jdbc工具包

JDBC工具类 介绍 JDBC全称是Java数据库连接&#xff08;Java Database connect&#xff09;&#xff0c;它是一套用于执行SQL语句的JavaAPI。应用程序可通过这台API连接到关系数据库&#xff0c;并使用SQL语句来完成对数据库中数据的查询、更新和删除等操作。 JDBC实现细节 从…

深入浅出C语言——排序

文章目录 排序的概念常见的排序算法冒泡排序选择排序插入排序希尔排序堆排序快速排序hoare版本挖坑法前后指针版本快速排序的非递归形式 归并排序递归版本非递归版本 计数排序排序算法复杂度及稳定性分析 排序的概念 排序就是使用使一串记录&#xff0c;按照其中的某个或某些关…