迪米特原则的理解和实践
迪米特原则(Law of Demeter,简称LoD),也被称为最少知识原则(Least Knowledge Principle,LKP),是面向对象设计中的一个重要原则。其核心思想是:一个对象应该对其他对象有最少的了解,即一个对象应该尽可能少地了解其直接对象之外的任何对象。本文将详细探讨迪米特原则的理论理解及其在Java实践中的应用。
一、迪米特原则的理论理解
迪米特原则的核心在于降低类之间的耦合度,提高模块的相对独立性。通过封装和信息隐藏,对象之间的通信应该通过抽象层进行,以减少对象之间的直接依赖。这种设计方式能够提高系统的可维护性和可扩展性,降低代码的依赖性,减少系统中的风险因素。
-
降低耦合度:
耦合度是指不同模块之间相互依赖的程度。过高的耦合度会导致代码难以维护和扩展。迪米特原则通过限制对象之间的直接通信,促使开发者使用接口或中间层来进行通信,从而有效地降低系统各部分之间的耦合度。 -
提高内聚力:
内聚力是指模块内部各元素间的紧密程度。高内聚力的模块功能更加专一,易于理解和修改。迪米特原则通过限制对象间的直接交流,促使开发者将功能相似的代码组织在一起,提高了模块的内聚力。 -
便于测试和重用:
通过遵循迪米特原则,每个类的功能更加单一和明确,这有助于对单个功能进行独立的测试,从而提高代码的可测试性。同时,减少类之间的直接依赖关系,使得类更加容易重用。 -
增强系统的可扩展性:
通过降低类之间的耦合,迪米特原则使得系统的某个部分在不改变其他部分的情况下可以进行修改或扩展,从而增强了系统的可扩展性。
二、迪米特原则的实践
在Java开发中,迪米特原则可以通过多种方式来实现,包括中介者模式、控制反转(IoC)和依赖注入(DI)、事件驱动编程以及模块化设计等。下面通过具体的代码示例来展示迪米特原则的实践。
示例一:中介者模式
当一个类需要与多个类进行交互时,可以使用中介者模式来降低类之间的直接依赖。中介者负责协调各个类之间的交互,从而减少类之间的直接通信。
// 中介者接口
interface Mediator {void send(String message, String colleagueName);
}// 具体中介者类
class ConcreteMediator implements Mediator {private ColleagueA colleagueA;private ColleagueB colleagueB;public void setColleagueA(ColleagueA colleagueA) {this.colleagueA = colleagueA;}public void setColleagueB(ColleagueB colleagueB) {this.colleagueB = colleagueB;}@Overridepublic void send(String message, String colleagueName) {if ("A".equals(colleagueName)) {colleagueA.receive(message);} else if ("B".equals(colleagueName)) {colleagueB.receive(message);}}
}// 同事类A
class ColleagueA {private Mediator mediator;public void setMediator(Mediator mediator) {this.mediator = mediator;}public void send(String message) {mediator.send(message, "B");}public void receive(String message) {System.out.println("ColleagueA received: " + message);}
}// 同事类B
class ColleagueB {private Mediator mediator;public void setMediator(Mediator mediator) {this.mediator = mediator;}public void send(String message) {mediator.send(message, "A");}public void receive(String message) {System.out.println("ColleagueB received: " + message);}
}// 测试类
public class MediatorPatternDemo {public static void main(String[] args) {Mediator mediator = new ConcreteMediator();ColleagueA colleagueA = new ColleagueA();ColleagueB colleagueB = new ColleagueB();mediator.setColleagueA(colleagueA);mediator.setColleagueB(colleagueB);colleagueA.setMediator(mediator);colleagueB.setMediator(mediator);colleagueA.send("Hello B");colleagueB.send("Hello A");}
}
在这个示例中,ColleagueA
和 ColleagueB
通过 Mediator
进行通信,而不是直接调用对方的方法。这降低了类之间的耦合度,提高了系统的可维护性和可扩展性。
示例二:控制反转(IoC)和依赖注入(DI)
控制反转和依赖注入允许我们将依赖关系外部化,并由容器或框架来管理。这样,类之间的依赖关系就变得更加灵活,降低了直接耦合。
// 接口
interface Service {void execute();
}// 具体服务类
class ConcreteService implements Service {@Overridepublic void execute() {System.out.println("Service executed");}
}// 客户端类
class Client {private Service service;// 构造器注入public Client(Service service) {this.service = service;}public void doSomething() {service.execute();}
}// 测试类
public class IoCDemo {public static void main(String[] args) {Service service = new ConcreteService();Client client = new Client(service);client.doSomething();}
}
在这个示例中,Client
类通过构造器注入的方式依赖 Service
接口,而不是直接依赖 ConcreteService
类。这使得 Client
类更加灵活,可以轻松地替换 Service
的实现。
示例三:迪米特原则的反面示例与推荐用法
下面通过一个业务场景来展示迪米特原则的反面示例和推荐用法。
反面示例:
// 经理类
public class Manager {public void checkGoodsCount(Staff staff) {List<Good> goodList = new ArrayList<>();for (int i = 0; i < 20; i++) {goodList.add(new Good());}staff.checkCount(goodList);}
}// 员工类
public class Staff {public void checkCount(List<Good> goodList) {System.out.println("商品数量为: " + goodList.size());}
}// 商品类
public class Good {
}// 测试类
public class Main {public static void main(String[] args) {Manager manager = new Manager();Staff staff = new Staff();manager.checkGoodsCount(staff);}
}
在这个反面示例中,Manager
类直接创建了 Good
对象的列表,并将其传递给 Staff
类。这违反了迪米特原则,因为 Manager
类不应该了解 Good
类的具体实现。
推荐用法:
// 经理类
public class Manager {public void checkGoodsCount(Staff staff) {staff.checkCount();}
}// 员工类
public class Staff {public void checkCount() {List<Good> goodList = new ArrayList<>();for (int i = 0; i < 20; i++) {goodList.add(new Good());}System.out.println("商品数量为: " + goodList.size());}
}// 商品类
public class Good {
}// 测试类
public class Main {public static void main(String[] args) {Manager manager = new Manager();Staff staff = new Staff();manager.checkGoodsCount(staff);}
}
在推荐用法中,Manager
类不再直接创建 Good
对象的列表,而是将创建列表的责任交给了 Staff
类。这样,Manager
类只需要知道 Staff
类的接口,而不需要了解 Good
类的具体实现,从而遵循了迪米特原则。
三、总结
迪米特原则是面向对象设计中的一个重要原则,它强调一个对象应该对其他对象有最少的了解。通过降低类之间的耦合度,提高模块的相对独立性,迪米特原则有助于我们设计出更加灵活、可维护性更高的软件系统。在Java开发中,我们可以利用中介者模式、控制反转(IoC)和依赖注入(DI)、事件驱动编程以及模块化设计等技术来实现迪米特原则。然而,过分追求迪米特原则可能导致设计过于复杂,增加不必要的抽象层和中介者。因此,在使用迪米特原则时应适度应用,结合其他设计原则,关注实际场景,避免盲目追求理论上的完美设计。
相关文章:
迪米特原则的理解和实践
迪米特原则(Law of Demeter,简称LoD),也被称为最少知识原则(Least Knowledge Principle,LKP),是面向对象设计中的一个重要原则。其核心思想是:一个对象应该对其他对象有最…...
jQuery零基础入门速通(中)
大家好,我是小黄。 在上一篇文章中,我们初步了解了jQuery的基本概念、环境搭建、选择器、基本的DOM操作以及事件处理。接下来,我们将继续深入探讨jQuery的DOM操作和事件处理,以及一些实用的技巧和高级用法。 五、高级DOM操作 5…...

【设计模式系列】中介者模式(十八)
一、什么是中介者模式 中介者模式(Mediator Pattern)是一种行为型设计模式,其核心思想是通过一个中介者对象来封装一系列对象之间的交互,使这些对象不需要相互显式引用。中介者模式提供了一个中介层,用以协调各个对象…...

PDF版地形图矢量出现的问题
项目描述:已建风电场道路测绘项目,收集到的数据为PDF版本的地形图,图上标注了项目竣工时期的现状,之后项目对施工区域进行了复垦恢复地貌,现阶段需要准确的知道实际复垦修复之后的道路及其它临时用地的面积 解决方法&…...

小迪安全第四十二天笔记 简单的mysql注入 mysql的基础知识 用户管理数据库模式 mysql 写入与读取 跨库查询
前言 之前的安全开发我们学习了 php联动数据库的模式 ,这个模式是现在常用的模式 这一节来学习 如何 进行数据库的注入和数据库相关知识 1、了解数据库的结构 我们使用 navicate连接数据库之后看一下 一共四层结构 库 》表》字段》数据 这个层级关系…...

11.25.2024刷华为OD
文章目录 HJ76 尼科彻斯定理(观察题,不难)HJ77 火车进站(DFS)HJ91 走格子方法,(动态规划,递归,有代表性)HJ93 数组分组(递归)语法知识…...

你真的会用饼图吗?JVS-智能BI饼图组件深度解析
在数据可视化的世界里,饼图是我们常见的一种可视化图形。在JVS-智能BI中提供了数据可视化饼图组件,接下来我通过这篇文章详细介绍,从配色方案到图形配置,从显示数据到提示信息,饼图的每一个细节配置。 饼图类图表概述…...

HarmonyOS Next 模拟器安装与探索
HarmonyOS 5 也发布了有一段时间了,不知道大家实际使用的时候有没有发现一些惊喜。当然随着HarmonyOS 5的更新也带来了很多新特性,尤其是 HarmonyOS Next 模拟器。今天,我们就来探索一下这个模拟器,看看它能给我们的开发过程带来什…...

医学机器学习:数据预处理、超参数调优与模型比较的实用分析
摘要 本文介绍了医学中的机器学习,重点阐述了数据预处理、超参数调优和模型比较的技术。在数据预处理方面,包括数据收集与整理、处理缺失值、特征工程等内容,以确保数据质量和可用性。超参数调优对模型性能至关重要,介绍了多种调…...

单片机知识总结(完整)
1、单片机概述 1.1. 单片机的定义与分类 定义: 单片机(Microcontroller Unit,简称MCU)是一种将微处理器、存储器(包括程序存储器和数据存储器)、输入/输出接口和其他必要的功能模块集成在单个芯片上的微型…...
【C++】auto和decltype类型推导关键字
1.C11关键字 auto和decltype是C11引入的关键字,负责类型的推导。所有不同的是: auto可直接用来定义变量,编译器会自动推导出变量的类型。decltype是推导出一个操作数的类型,然后用这个类型再去定义。 2.两者区别 尽管两者都是宏…...

OGRE 3D----3. OGRE绘制自定义模型
在使用OGRE进行开发时,绘制自定义模型是一个常见的需求。本文将介绍如何使用OGRE的ManualObject类来创建和绘制自定义模型。通过ManualObject,开发者可以直接定义顶点、法线、纹理坐标等,从而灵活地构建各种复杂的几何体。 Ogre::ManualObject 是 Ogre3D 引擎中的一个类,用…...
ARM + Linux 开发指南
随想:想写一个系列来讲如何嵌入式开发,然后能形成一个知识体系,帮助那些刚刚做嵌入开发的同学们. 1. ARM Linux从开机到Linux完全启动的流程和代码分析 ARM Linux从开机到完全启动的流程与代码分析 ARM Linux的启动过程主要涉及从设备上电开始,到Linux内核完全启动并进入…...

facebook欧洲户开户条件有哪些又有何优势?
在当今数字营销时代,Facebook广告已成为企业推广产品和服务的重要渠道。而为了更好地利用这一平台,广告主们需要理解不同类型的Facebook广告账户。Facebook广告账户根据其属性可分为多种类型,包括个人广告账户、企业管理(BM&#…...
算法训练(leetcode)二刷第三十一天 | 1049. 最后一块石头的重量 II、494. 目标和、*474. 一和零
刷题记录 1049. 最后一块石头的重量 II*494. 目标和二维数组滚动数组 *474. 一和零 1049. 最后一块石头的重量 II leetcode题目地址 本题与416. 分割等和子集类似。依旧是01背包问题,本题尽可能将石头分为相等(相近)的两堆,然后…...
软件测试丨Pytest生命周期与数据驱动
Pytest的生命周期概述 Pytest 是一个强大的测试框架,提供了丰富的特性来简化测试执行。它的生命周期包括多个阶段,涉及从准备测试、执行测试到报告结果的完整流程。因此,理解Pytest的生命周期将帮助我们更好地设计和管理测试用例。 开始阶段…...

Figma入门-原型交互
Figma入门-原型交互 前言 在之前的工作中,大家的原型图都是使用 Axure 制作的,印象中 Figma 一直是个专业设计软件。 最近,很多产品朋友告诉我,很多原型图都开始用Figma制作了,并且很多组件都是内置的,对…...

网络安全防范技术
1 实践内容 1.1 安全防范 为了保障"信息安全金三角"的CIA属性、即机密性、完整性、可用性,信息安全领域提出了一系列安全模型。其中动态可适应网络安全模型基于闭环控制理论,典型的有PDR和P^2DR模型。 1.1.1 PDR模型 信息系统的防御机制能抵抗…...

Java - JSR223规范解读_在JVM上实现多语言支持
文章目录 1. 概述2. 核心目标3. 支持的脚本语言4. 主要接口5. 脚本引擎的使用执行JavaScript脚本执行groovy脚本1. Groovy简介2. Groovy脚本示例3. 如何在Java中集成 Groovy4. 集成注意事项 6. 与Java集成7. 常见应用场景8. 优缺点9. 总结 1. 概述 JSR223(Java Spe…...

win10系统部署RAGFLOW+Ollama教程
本篇主要基于linux服务器部署ragflowollama,其他操作系统稍有差异但是大体一样。 一、先决条件 CPU ≥ 4核; RAM ≥ 16 GB; 磁盘 ≥ 50 GB; Docker ≥ 24.0.0 & Docker Compose ≥ v2.26.1。 如果尚未在本地计算机ÿ…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...

《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

java高级——高阶函数、如何定义一个函数式接口类似stream流的filter
java高级——高阶函数、stream流 前情提要文章介绍一、函数伊始1.1 合格的函数1.2 有形的函数2. 函数对象2.1 函数对象——行为参数化2.2 函数对象——延迟执行 二、 函数编程语法1. 函数对象表现形式1.1 Lambda表达式1.2 方法引用(Math::max) 2 函数接口…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...

解析“道作为序位生成器”的核心原理
解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制,重点解析"道作为序位生成器"的核心原理与实现框架: 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...
深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙
WebGL:在浏览器中解锁3D世界的魔法钥匙 引言:网页的边界正在消失 在数字化浪潮的推动下,网页早已不再是静态信息的展示窗口。如今,我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室,甚至沉浸式的V…...
【系统架构设计师-2025上半年真题】综合知识-参考答案及部分详解(回忆版)
更多内容请见: 备考系统架构设计师-专栏介绍和目录 文章目录 【第1题】【第2题】【第3题】【第4题】【第5题】【第6题】【第7题】【第8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16题】【第17题】【第18题】【第19题】【第20~21题】【第…...