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

SOLID原理:用Golang的例子来解释

随着软件系统变得越来越复杂,编写模块化、灵活和易于理解的代码非常重要。实现这一目标的方法之一是遵循SOLID原则。这些原则是由罗伯特-C-马丁(Robert C. Martin)提出的,以帮助开发人员创建更容易维护、测试和扩展的代码。
本文将对每个SOLID原则进行概述,并通过用Golang编写的例子说明它们在贸易生态系统中的应用。
单一责任原则(SRP):该原则指出,一个类应该只有一个变化的理由。如果我们违反了这一原则,这个类就会有多个责任,使得它更难维护、测试和扩展。这可能导致代码紧密耦合,难以重用,并且容易出错。
在一个贸易生态系统中,一个贸易类应该负责存储和处理贸易数据。另一个类,如TradeValidator,可以负责根据业务规则来验证交易。通过分离这些关注点,每个类可以更容易地被测试和维护。

type Trade struct {TradeID intSymbol stringQuantity float64Price float64
}type TradeRepository struct {db *sql.DB
}func (tr *TradeRepository) Save(trade *Trade) error {_, err := tr.db.Exec("INSERT INTO trades (trade_id, symbol, quantity, price) VALUES (?, ?, ?, ?)", trade.TradeID, trade.Symbol, trade.Quantity, trade.Price)if err != nil {return err}return nil
}type TradeValidator struct {}func (tv *TradeValidator) Validate(trade *Trade) error {if trade.Quantity <= 0 {return errors.New("Trade quantity must be greater than zero")}if trade.Price <= 0 {return errors.New("Trade price must be greater than zero")}return nil
}

开放-封闭原则(OCP):这一原则指出,类应该是开放的,可以进行扩展,但对修改来说是封闭的。如果我们违反了这一原则,我们可能不得不修改现有的代码来增加新的功能,这可能会引入错误,使代码难以维护。这也会导致代码难以测试和重用。
在一个贸易生态系统中,TradeProcessor类应该被设计成对扩展开放,但对修改封闭。这意味着,如果增加了新的交易类型,TradeProcessor类应该能够处理它们而不需要修改现有的代码。这可以通过定义一个处理交易的接口并为每个交易类型实现它来实现。

type TradeProcessor interface {Process(trade *Trade) error
}type FutureTradeProcessor struct {}func (ftp *FutureTradeProcessor) Process(trade *Trade) error {// process future tradereturn nil
}type OptionTradeProcessor struct {}func (otp *OptionTradeProcessor) Process(trade *Trade) error {// process option tradereturn nil
}

里氏替换原则(LSP):该原则指出,子类型应该可以替代其基类型。如果我们违反了这一原则,我们可能会引入出乎意料和不一致的行为,这可能会导致难以追踪的错误。这也会使我们很难写出能与各种不同类型一起工作的代码。
在一个贸易生态系统中,FutureTrade类应该是Trade类的一个子类型,这意味着它应该能够代替Trade类而不引起任何问题。例如,如果一个TradeProcessor类期望一个Trade对象,但收到一个FutureTrade对象,它应该仍然能够处理交易而不会有任何问题。

type Trade interface {Process() error
}type FutureTrade struct {Trade
}func (ft *FutureTrade) Process() error {// process future tradereturn nil
}

接口隔离原则(ISP):该原则指出,客户不应该被迫依赖他们不使用的接口。如果我们违反了这一原则,我们的接口可能会过大,并且包含与某些客户无关的方法,这可能会导致代码难以理解和维护。这也会导致代码无法重用,而且会造成模块之间不必要的耦合。
在一个交易生态系统中,一个Trade接口应该只包括与所有类型的交易相关的方法。可以创建额外的接口,比如OptionTrade或FutureTrade,以包括那些交易类型所特有的方法。这样一来,只需要处理特定类型的交易的代码就可以依赖适当的接口,而不是一个包含不必要的方法的更大的接口。

type Trade interface {Process() error
}type OptionTrade interface {CalculateImpliedVolatility() error
}type FutureTrade struct {Trade
}func (ft *FutureTrade) Process() error {// process future tradereturn nil
}type OptionTrade struct {Trade
}func (ot *OptionTrade) Process() error {// process option tradereturn nil
}func (ot *OptionTrade) CalculateImpliedVolatility() error {// calculate implied volatilityreturn nil
}

依赖性反转原则(DIP):这一原则指出,高层模块不应依赖低层模块。相反,两者都应该依赖于抽象的东西。如果我们违反了这个原则,我们可能会有难以测试和重用的代码,而且是紧密耦合的。这也会导致代码难以维护和扩展。
在一个贸易生态系统中,TradeProcessor类应该依赖于一个接口,如TradeService,而不是一个具体的实现,如SqlServerTradeRepository。这样一来,TradeService接口的不同实现可以互换,而不影响TradeProcessor类,这可以使其更容易维护和测试。例如,可以用MongoDBTradeRepository代替SqlServerTradeRepository,而不用修改TradeProcessor类。

type TradeService interface {Save(trade *Trade) error
}type TradeProcessor struct {tradeService TradeService
}func (tp *TradeProcessor) Process(trade *Trade) error {err := tp.tradeService.Save(trade)if err != nil {return err}// process tradereturn nil
}type SqlServerTradeRepository struct {db *sql.DB
}func (str *SqlServerTradeRepository) Save(trade *Trade) error {_, err := str.db.Exec("INSERT INTO trades (trade_id, symbol, quantity, price) VALUES (?, ?, ?, ?)", trade.TradeID, trade.Symbol, trade.Quantity, trade.Price)if err != nil {return err}return nil
}type MongoDbTradeRepository struct {session *mgo.Session
}func (mdtr *MongoDbTradeRepository) Save(trade *Trade) error {collection := mdtr.session.DB("trades").C("trade")err := collection.Insert(trade)if err != nil {return err}return nil
}

综上所述,如果我们不使用SOLID原则,我们最终可能会得到难以维护、测试和重用的代码。这可能会导致错误,性能差,以及无法为代码添加新功能。通过遵循这些原则,我们可以创建更加模块化、更加灵活、更加容易理解的代码,这可以使软件整体上更加完善。

相关文章:

SOLID原理:用Golang的例子来解释

随着软件系统变得越来越复杂&#xff0c;编写模块化、灵活和易于理解的代码非常重要。实现这一目标的方法之一是遵循SOLID原则。这些原则是由罗伯特-C-马丁&#xff08;Robert C. Martin&#xff09;提出的&#xff0c;以帮助开发人员创建更容易维护、测试和扩展的代码。 本文将…...

mysql是如何使用索引的?

摘自官网 MySQL使用索引进行以下操作: WHERE条件中,快速查找匹配的行。(快速查询数据) 从准备查询的数据中消除多余行。如果可以在多个索引之间进行选择,则MySQL通常会使用查找最少行数的索引。 如果表具有多列索引,那么优化器可以使用索引的任何最左前缀来查找行。 举例来…...

自动驾驶IPO第一股及商业化行业标杆 Mobileye

一、Mobileye 简介 Mobileye 是全球领先的自动驾驶技术公司&#xff0c;成立于 1999 年&#xff0c;总部位于以色列耶路撒冷。公司专注于开发视觉感知技术和辅助驾驶系统 (ADAS)&#xff0c;并在自动驾驶领域处于领先地位。Mobileye 是高级驾驶辅助系统&#xff08;ADAS&#…...

Linux前后端程序部署

1.总述 首先安装包类型分为 二进制发布包安装:找到对应自己的linux平台版本(CentOS还是redhat等),的具体压缩文件,解压修改配置 源码编译安装:需要自己进行编译 对于redhat安装包,可以使用rpm命令进行安装,但是rpm命令安装不能够解决依赖库的问题,常用的rpm命令,只用于卸载…...

手把手 S32K344移植FreeRTOS

版本信息 RTD:2.0.0.2022 S32DS:3.4.0.2020 下载 从S32K3参考软件下载FreeTROS FreeRTOS安装链接&#xff1a;https://www.nxp.com/webapp/swlicensing/sso/downloadSoftware.sp?catidSW32K3-REFSW-D 根据S32DS版本和S32K3 RTD 2.0.0 Package找到对应的FreeRTOS的zip安装…...

《云原生安全攻防》-- 云原生安全概述

从本节课程开始&#xff0c;我们将正式踏上云原生安全的学习之旅。在深入探讨云原生安全的相关概念之前&#xff0c;让我们先对云原生有一个全面的认识。 什么是云原生呢? 云原生&#xff08;Cloud Native&#xff09;是一个组合词&#xff0c;我们把它拆分为云和原生两个词来…...

综合分享1

VM及安装配置windows server 2008 1&#xff09;安装配置VM 确保是否正确安装&#xff1a; 1&#xff09;检查本地“网络与internal设置”中的虚拟网卡是否创建成功&#xff08;vmnet1和vmnet8&#xff09; 2&#xff09;必须通过services.msc查看vmware的所有是否已经…...

Redis -- set集合

挑战自己&#xff0c;每天进步一点点&#xff0c;成就将属于不停止脚步的你。 目录 Redis集合&#xff1f; 集合基本命令 sadd smembers sismember scard spop srandmember smove srem 集合间操作 sinter sinterstore sunion sdiff sdiifstore Redis集合&#…...

明天是几号(c++题解)

题目描述 题目描述 在某国&#xff0c;每年有 个月&#xff0c;每个月有 天。 求 年 月 日的下一天的日期。 输入格式 第一行&#xff1a;两个整数 。 第二行&#xff1a;三个整数 输出格式 输出三个整数&#xff0c;表示 年 月 日的下一天的日期。 样例 样例…...

PHP安装后错误处理

一&#xff1a;问题 安装PHP后提示错误如下 二&#xff1a;解决 1&#xff1a;Warning: Module mysqli already loaded in Unknown on line 0解决 原因&#xff1a;通过php.ini配置文件开启mysqli扩展的时候&#xff0c;开启了多次 解决&#xff1a;将php.ini配置文件中多个…...

Unity3D开发之鼠标单双击判断

在开发游戏和交互式应用程序时&#xff0c;经常需要对用户的鼠标点击进行准确的响应。其中&#xff0c;单击和双击事件的判断是常见需求之一。本文将介绍如何在Unity中优雅地实现鼠标单双击判断&#xff0c;使代码结构清晰、易读、易维护。 背景 在许多项目中&#xff0c;我们…...

openGauss学习笔记-214 openGauss 性能调优-确定性能调优范围

文章目录 openGauss学习笔记-214 openGauss 性能调优-确定性能调优范围214.1 性能因素214.2 调优范围确定 openGauss学习笔记-214 openGauss 性能调优-确定性能调优范围 数据库性能调优通常发生在用户对业务的执行效率不满意&#xff0c;期望通过调优加快业务执行的情况下。正…...

JAVA——Stream流

1.Stream流的作用&#xff08;流水线&#xff09; 结合了Lambda表达式&#xff0c;简化集合、数组的操作&#xff1b; 2.Stream流的使用步骤 ①先得到一条Stream流&#xff08;流水线&#xff09;&#xff0c;并将数据放上去&#xff1b; ②利用Stream流中的API进行各种操作…...

QXlsx Qt操作excel(1)

QXlsx 是一个用于处理Excel文件的开源C库。它允许你在你的C应用程序中读取和写入Microsoft Excel文件&#xff08;.xlsx格式&#xff09;。该库支持多种操作&#xff0c;包括创建新的工作簿、读取和写入单元格数据、格式化单元格、以及其他与Excel文件相关的功能。 关于QXlsx的…...

20240131在ubuntu20.04.6下使用whisper不同模式的比对

20240131在ubuntu20.04.6下使用whisper不同模式的比对 2024/1/31 16:07 首先你要有一张NVIDIA的显卡&#xff0c;比如我用的PDD拼多多的二手GTX1080显卡。【并且极其可能是矿卡&#xff01;】 2、请正确安装好NVIDIA最新的驱动程序和CUDA。可选安装&#xff01; 3、配置whisper…...

HTTP相关问题

目录 1.从输入URL到页面展示到底发生了什么&#xff1f; 2.HTTP状态码有哪些&#xff1f; 2.1 2XX(成功状态码) 2.2 3XX(重定向状态码) 2.3 4XX(客户端错误状态码) 2.4 5XX(服务端错误状态码) 3.HTTP 请求头中常见的字段有哪些&#xff1f; 4.HTTP和HTTPS有什么区别&…...

闲人闲谈PS之五十三——离散制造中的魔鬼--物料套裁

惯例闲话&#xff1a;最近和老婆大人商议买车事宜&#xff0c;闲人以为会陷入买油车还是电车的纠结&#xff0c;没想到老婆大人无比坚定&#xff0c;买电车。在买车这方面&#xff0c;老婆的想法居然比闲人超前。闲人对车定位在代步工具&#xff0c;2年前&#xff0c;对车还是印…...

Dell服务器iDRAC9忘记密码, 通过RACADM工具不重启 重置密码

系列文章目录 文章目录 系列文章目录前言一、RACADM工具二、linux环境1.解压安装RACADM工具测试RACADM工具重置iDRAC密码 Windows环境 前言 一、RACADM工具 RACADM工具 官网参考信息 https://www.dell.com/support/kbdoc/zh-cn/000126703/%E5%A6%82%E4%BD%95-%E9%87%8D%E7%BD…...

2024年Java架构篇之数据结构与算法面试题

2024年Java实战面试题_java 5 年 面试-CSDN博客 2024年Java架构篇之数据结构与算法面试题 1、判断一个数是否是2的N次方&#xff0c;比如2、4、8、16是6、10不是 1:01、2:10、3:011、4:100、7:0111、8:1000、15:01111、16:10000 if(n&(n-1) 0) 那么n就是2的次方 n > 1...

蓝桥杯刷题day06——平均

1、题目描述 有一个长度为n 的数组&#xff08;n 是 10 的倍数&#xff09;&#xff0c;每个数ai都是区间 [0,9] 中的整数。 小明发现数组里每种数出现的次数不太平均&#xff0c;而更改第i 个数的代价为bi&#xff0c; 他想更改若干个数的值使得这10 种数出现的次数相等&…...

国防科技大学计算机基础课程笔记02信息编码

1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制&#xff0c;因此这个了16进制的数据既可以翻译成为这个机器码&#xff0c;也可以翻译成为这个国标码&#xff0c;所以这个时候很容易会出现这个歧义的情况&#xff1b; 因此&#xff0c;我们的这个国…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

【笔记】WSL 中 Rust 安装与测试完整记录

#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统&#xff1a;Ubuntu 24.04 LTS (WSL2)架构&#xff1a;x86_64 (GNU/Linux)Rust 版本&#xff1a;rustc 1.87.0 (2025-05-09)Cargo 版本&#xff1a;cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...

CSS | transition 和 transform的用处和区别

省流总结&#xff1a; transform用于变换/变形&#xff0c;transition是动画控制器 transform 用来对元素进行变形&#xff0c;常见的操作如下&#xff0c;它是立即生效的样式变形属性。 旋转 rotate(角度deg)、平移 translateX(像素px)、缩放 scale(倍数)、倾斜 skewX(角度…...

Leetcode33( 搜索旋转排序数组)

题目表述 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...

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

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

LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)

在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...