当前位置: 首页 > 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) 。 当时我们说阻塞队列最大的用途, 就是用来实现生产者消费者模型。 生产者消费者模型是后端开发的常用编程方式, 它存在诸多好处: 解耦合支持并发支持忙闲不均削峰…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)

题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...

Python训练营-Day26-函数专题1:函数定义与参数

题目1&#xff1a;计算圆的面积 任务&#xff1a; 编写一个名为 calculate_circle_area 的函数&#xff0c;该函数接收圆的半径 radius 作为参数&#xff0c;并返回圆的面积。圆的面积 π * radius (可以使用 math.pi 作为 π 的值)要求&#xff1a;函数接收一个位置参数 radi…...

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法

用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...

门静脉高压——表现

一、门静脉高压表现 00:01 1. 门静脉构成 00:13 组成结构&#xff1a;由肠系膜上静脉和脾静脉汇合构成&#xff0c;是肝脏血液供应的主要来源。淤血后果&#xff1a;门静脉淤血会同时导致脾静脉和肠系膜上静脉淤血&#xff0c;引发后续系列症状。 2. 脾大和脾功能亢进 00:46 …...

接口 RESTful 中的超媒体:REST 架构的灵魂驱动

在 RESTful 架构中&#xff0c;** 超媒体&#xff08;Hypermedia&#xff09;** 是一个核心概念&#xff0c;它体现了 REST 的 “表述性状态转移&#xff08;Representational State Transfer&#xff09;” 的本质&#xff0c;也是区分 “真 RESTful API” 与 “伪 RESTful AP…...