当前位置: 首页 > news >正文

DIP的实际举例

SOLID原则。

依赖倒置原则(DIP)的核心是高层模块不应该依赖于低层模块,二者都应该依赖于抽象(接口或抽象类)

例如,随着业务的发展,订单总金额的计算规则可能需要根据不同的客户类型或促销活动进行调整。如果最初没有使用接口来抽象计算逻辑,那么可能需要直接修改具体的业务代码,这会增加代码的修改风险和维护成本。而使用接口可以方便地实现不同的计算策略,通过依赖注入等方式进行切换,提高系统的灵活性和可扩展性。
接下来我们逐步优化,把他变得满足SRP和OCP、DIP原则了。

循环累加

public class Order {private double[] productPrices;public Order(double[] productPrices) {this.productPrices = productPrices;}// 计算订单总金额的方法public double calculateTotalAmount() {double total = 0;for (double price : productPrices) {total += price;}return total;}
}

当业务发展,需要根据不同客户类型(比如普通客户、VIP 客户)和促销活动(比如满减、折扣)来调整订单总金额的计算规则时,就需要直接修改 calculateTotalAmount 方法的代码。例如,VIP 客户享受 9 折优惠,满 100 减 20 的促销活动,代码修改如下:

public class Order {private double[] productPrices;private String customerType;public Order(double[] productPrices, String customerType) {this.productPrices = productPrices;this.customerType = customerType;}// 计算订单总金额的方法,修改后变得复杂public double calculateTotalAmount() {double total = 0;for (double price : productPrices) {total += price;}if ("VIP".equals(customerType)) {total *= 0.9;}if (total >= 100) {total -= 20;}return total;}
}

这种直接修改的方式,随着业务规则的不断增加和变化,代码会变得越来越复杂和难以维护,修改一处可能会影响到其他部分的逻辑,增加了出错的风险。

抽象工厂

我们发现,订单类和计算金额的修改原因、修改速率不一样,根据SRP原则,利用抽象工厂模式,把他抽出来,如下。

// 订单类
public class Order {private double[] productPrices;private String customerType;public Order(double[] productPrices, String customerType) {this.productPrices = productPrices;this.customerType = customerType;}// 计算总金额,依赖工厂类public double calculateTotalAmount() {return OrderTotalCalculatorFactory.calculateTotal(productPrices, customerType);}
}// 订单总金额计算工厂类
public class OrderTotalCalculatorFactory {public static double calculateTotal(double[] productPrices, String customerType) {if ("Regular".equals(customerType)) {double total = 0;for (double price : productPrices) {total += price;}return total;} else if ("VIP".equals(customerType)) {double total = 0;for (double price : productPrices) {total += price;}total *= 0.9;return total;} else {double total = 0;for (double price : productPrices) {total += price;}if (total >= 100) {total -= 20;}return total;}}
}

引入抽象类

如果再有新的计费类型时,我们需要修改OrderTotalCalculatorFactory ,再添加一个if-else,然后在里面写代码,违反了OCP原则。所以我们不把具体代码写到OrderTotalCalculatorFactory 里,而是再抽一层,可以是接口,也可以不是。(这样不是说没有改动,但是改动点小了。是扩展本类,而不是修改)
但是为了专业(把相同的抽出来,作为上层),我们没有理由不写成接口。
此外如果再想加一个过期时间校验功能(我们的优惠、会员等都是有时间的),先校验,然后再计算金额。这个时候就体现出接口的好处来了。

这样就是所谓的DIP了:由原来的order订单依赖于金额计算,现在加了一个接口,二者都依赖于这个接口了。

// 订单总金额计算策略接口
public interface OrderTotalCalculator {double calculateTotal(double[] productPrices);
}// 普通客户计算策略实现类
public class RegularCustomerCalculator implements OrderTotalCalculator {@Overridepublic double calculateTotal(double[] productPrices) {double total = 0;for (double price : productPrices) {total += price;}return total;}
}// VIP客户计算策略实现类
public class VIPCustomerCalculator implements OrderTotalCalculator {@Overridepublic double calculateTotal(double[] productPrices) {double total = 0;for (double price : productPrices) {total += price;}total *= 0.9;return total;}
}// 工厂类
public class OrderTotalCalculatorFactory {public static OrderTotalCalculator createCalculator(String customerType) {if ("Regular".equals(customerType)) {return new RegularCustomerCalculator();} else if ("VIP".equals(customerType)) {return new VIPCustomerCalculator();} // 目前只有这两种情况,后续可扩展return null;}
}// 组合优于继承
public class Order {private double[] productPrices;private String customerType;private OrderTotalCalculator calculator;public Order(double[] productPrices, String customerType) {this.productPrices = productPrices;this.customerType = customerType;this.calculator = OrderTotalCalculatorFactory.createCalculator(customerType);}public double calculateTotalAmount() {return calculator.calculateTotal(productPrices);}
}

相关文章:

DIP的实际举例

SOLID原则。 依赖倒置原则(DIP)的核心是高层模块不应该依赖于低层模块,二者都应该依赖于抽象(接口或抽象类) 例如,随着业务的发展,订单总金额的计算规则可能需要根据不同的客户类型或促销活动…...

DeepSeek引领目标检测新趋势:如何通过知识蒸馏优化模型性能

目录 一、知识蒸馏是什么? 二、知识蒸馏在目标检测中的重要性 提升实时性 跨任务迁移学习 三、如何使用知识蒸馏优化目标检测? 训练教师模型 生成软标签 训练学生模型 调节温度参数 多教师蒸馏(可选) 四、案例分享 定…...

vue2.x 中父组件通过props向子组件传递数据详细解读

1. 父组件向子组件传递数据的步骤 在子组件中定义 props: 子组件通过 props 选项声明它期望接收的数据。props 可以是数组形式(简单声明)或对象形式(支持类型检查和默认值)。 在父组件中使用子组件时绑定 props&#x…...

安装PHPStudy 并搭建DVWA靶场

目录 一、PHPStudy 简介 二、DVWA 简介 三、安装 PHPStudy 四:安装 DVWA 一、PHPStudy 简介 phpstudy傻瓜式的一键启动,支持WAMP、WNMP、LAMP、LNMP,一键切换环境(nginxapahce),一键切换PHP版本(5.1-7…...

RoCBert:具有多模态对比预训练的健壮中文BERT

摘要 大规模预训练语言模型在自然语言处理(NLP)任务上取得了最新的最优结果(SOTA)。然而,这些模型容易受到对抗攻击的影响,尤其是对于表意文字语言(如中文)。 在本研究中&#xff0…...

【C】堆的应用1 -- 堆排序

之前学习了堆,堆的一棵以顺序结构存储的完全二叉树,堆本身又氛围大根堆和小根堆,假设以大根堆为例,由于堆顶部元素是一棵二叉树里面最大的元素,所以如果每次都取堆顶的元素,那么取出的元素就是一个降序排列…...

BGP配置华为——路径优选验证

实验拓扑 实验要求 实现通过修改AS-Path属性来影响路径选择实现通过修改Local_Preference属性来影响路径选择实现通过修改MED属性来影响路径选择实现通过修改preferred-value属性来影响路径选择 实验配置与效果 1.改名与IP配置 2.as300配置OSPF R3已经学到R2和R4的路由 3.…...

【原创】Windows11安装WSL“无法解析服务器的名称或地址”问题解决方法

原因分析 出现这个问题一开始以为WSL设置了某个服务器,但是通过运行 nslookup www.microsoft.com 出现下面的提示 PS C:\Windows\system32> nslookup www.microsoft.com 服务器: UnKnown Address: 2408:8000:XXXX:2b00:8:8:8:8非权威应答: 名称: e13678…...

【CS285】高斯策略对数概率公式的学习笔记

公式介绍 在【CS285】中提到了高斯策略对数概率公式的公式如下: log ⁡ π θ ( a t ∣ s t ) − 1 2 ∥ f ( s t ) − a t ∥ Σ 2 const \log \pi_{\theta}(\mathbf{a}_t | \mathbf{s}_t) -\frac{1}{2} \left\| f(\mathbf{s}_t) - \mathbf{a}_t \right\|_{\S…...

R与RStudio简介及安装

目录 一、R与RStudio关系 二、R简介 2.1. 发展历史 2.2. R语言特点 三、安装指南 3.1 R安装指南 3.2 R studio安装指南 一、R与RStudio关系 R是统计领域广泛使用的工具,属于GNU系统的一个自由、免费、源代码开放的软件,是 用于统计计算和统计绘图…...

TTL和CMOS的区别【数电速通】

CMOS电平:电压范围在3~15V;常见电压在12V。 TTL电平:电压范围在0~5V,常见都是5V CMOS的特点:电平由电源VDD​ 决定,而不是外部电源电平。 COMS电路的使用注意事项 我们在使用CMOS…...

Linux红帽:RHCSA认证知识讲解(二)配置网络与登录本地远程Linux主机

Linux红帽:RHCSA认证知识讲解(二)配置网络与登录本地远程Linux主机 前言一、使用命令行(nmcli 命令)配置网络,配置主机名第一步第二步修改主机名称 二、使用图形化界面(nmtui 命令)配…...

Threejs教程一【三要素】

场景 场景是一个容器,用于容纳所有的物体、光源、相机等元素。 // 创建场景 const scene new THREE.Scene(); //修改背景颜色,颜色支持十六进制、rgb、hsl、贴图等 scene.background new THREE.Color(0x000000);相机 相机决定了渲染的结果&#xff…...

3-1 WPS JS宏工作簿的新建与保存(批量新建工作簿)学习笔记

************************************************************************************************************** 点击进入 -我要自学网-国内领先的专业视频教程学习网站 *******************************************************************************************…...

明日方舟一键端+单机+联网+安装教程+客户端apk

为了学习和研究软件内含的设计思想和原理,本人花心血和汗水带来了搭建教程!!! 教程不适于服架设,严禁服架设!!!请牢记!!! 教程仅限学习使用&…...

Redis基操

redis 存储在内存中 key-value存储 主要存储热点数据(短时间大量的访客去访问) 启动命令 redis-server.exe redis.windows.conf 客户端链接redis服务器 redis-cli.exe redis-cli.exe -h localhost -p 6379 redis-cli.exe -h localhost -p 6379 -a 123456 退出 exit 命令不区分…...

学习笔记03——《深入理解Java虚拟机(第三版)》类加载机制知识总结与面试核心要点

《深入理解Java虚拟机(第三版)》类加载机制知识总结与面试核心要点 一、章节核心脉络 核心命题:JVM如何将.class文件加载到内存并转换为运行时数据结构? 核心流程:加载 → 验证 → 准备 → 解析 → 初始化 → 使用 →…...

w227springboot旅游管理系统设计与实现

🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...

漏洞文字版表述一句话版本(漏洞危害以及修复建议),通常用于漏洞通报中简洁干练【持续更新中】

漏洞文字版表述一句话版本(漏洞危害以及修复建议) SQL注入漏洞 危害描述: SQL注入漏洞允许攻击者通过构造恶意的SQL语句,绕过应用程序的安全检查,直接访问或操作数据库。这可能导致数据泄露、数据篡改、甚至数据库被删除等严重后果&#xf…...

项目——仿RabbitMQ实现消息队列

1.项目介绍 曾经在学习Linux的过程中,我们学习过阻塞队列 (BlockingQueue) 。 当时我们说阻塞队列最大的用途, 就是用来实现生产者消费者模型。 生产者消费者模型是后端开发的常用编程方式, 它存在诸多好处: 解耦合支持并发支持忙闲不均削峰…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found"​, "n…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...

Oracle11g安装包

Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...

前端高频面试题2:浏览器/计算机网络

本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...