15分钟学 Go 第 56 天:架构设计基本原则

第56天:架构设计基本原则

学习目标

理解和掌握基本的架构设计原则,以提升软件系统的可维护性、可扩展性和可重用性。

内容提纲

  1. 架构设计原则概述
  2. 常见架构设计原则
    • 单一职责原则 (SRP)
    • 开放/封闭原则 (OCP)
    • 里氏替换原则 (LSP)
    • 接口分离原则 (ISP)
    • 依赖反转原则 (DIP)
  3. 架构设计的最佳实践
  4. 示例代码
  5. 运行流程图
  6. 总结

1. 架构设计原则概述

架构设计原则是开发软件系统时用以指导设计和开发过程的基本准则。这些原则帮助开发者创建更优秀的软件架构,从而确保可维护性、可扩展性、可重用性和良好的性能。

2. 常见架构设计原则

2.1 单一职责原则 (SRP)

定义:一个类应该只有一个原因引起它的变化。换句话说,每个类应该专注于完成一项职责。

示例代码

package mainimport "fmt"// 用户管理类
type User struct {Name stringAge  int
}// 发送邮件功能
type EmailService struct{}func (es *EmailService) SendEmail(email string) {fmt.Printf("Sending email to %s\n", email)
}// 用户服务
type UserService struct {emailService *EmailService
}func (us *UserService) CreateUser(name string, age int, email string) {user := User{Name: name, Age: age}fmt.Printf("User created: %+v\n", user)us.emailService.SendEmail(email)
}func main() {emailService := &EmailService{}userService := &UserService{emailService: emailService}userService.CreateUser("Alice", 30, "alice@example.com")
}

运行流程图

+---------------------+
|  创建 UserService   |
|  +----------------+  |
|  | EmailService   |  |
|  +----------------+  |
+---------------------+|+---------------------+|  CreateUser        |+---------------------+|+---------------------+|  发送邮件          |+---------------------+

2.2 开放/封闭原则 (OCP)

定义:软件实体(类、模块、函数等)应当对扩展开放,对修改封闭。即,应该可以通过添加新功能或新代码来扩展系统,而不需要去修改现有的代码。

示例代码

package mainimport "fmt"// Shape 接口
type Shape interface {Area() float64
}// 矩形
type Rectangle struct {Width, Height float64
}func (r Rectangle) Area() float64 {return r.Width * r.Height
}// 圆
type Circle struct {Radius float64
}func (c Circle) Area() float64 {return 3.14 * c.Radius * c.Radius
}// 计算总面积
func TotalArea(shapes []Shape) float64 {total := 0.0for _, shape := range shapes {total += shape.Area()}return total
}func main() {shapes := []Shape{Rectangle{Width: 10, Height: 5},Circle{Radius: 7},}fmt.Printf("Total Area: %.2f\n", TotalArea(shapes))
}

运行流程图

+---------------------+
|   TotalArea        |
+---------------------+|
+----------+----------+
|                     |
|                     |
+                     +
|                     |
+--------+------------+
|  计算每个 Area     |
+---------------------+

2.3 里氏替换原则 (LSP)

定义:子类对象能够替换父类对象,并且在程序运行中不会影响程序的正常运行。

示例代码

package mainimport "fmt"// Bird 接口
type Bird interface {Fly() string
}// Sparrow 是 Bird 的实现
type Sparrow struct{}func (s Sparrow) Fly() string {return "Sparrow flying"
}// Ostrich 是 Bird 的实现,但不能飞
type Ostrich struct{}func (o Ostrich) Fly() string {return "Ostrich can't fly"
}// 使用 Bird 接口
func MakeBirdFly(bird Bird) {fmt.Println(bird.Fly())
}func main() {sparrow := Sparrow{}ostrich := Ostrich{}MakeBirdFly(sparrow) // 输出: Sparrow flyingMakeBirdFly(ostrich) // 输出: Ostrich can't fly
}

运行流程图

+---------------------+
|   MakeBirdFly      |
+---------------------+|
+----------+----------+
|                     |
|                     |
+                     +
|                     |
+--------+------------+
|  调用 Fly 方法     |
+---------------------+

2.4 接口分离原则 (ISP)

定义:客户端不应该被迫依赖于它不使用的方法。即接口应该尽可能的细小,客户端只需关注自身需要的方法。

示例代码

package mainimport "fmt"// 形状接口
type Shape interface {Area() float64
}// 3D 形状接口
type ThreeDimensionalShape interface {ShapeVolume() float64
}// 矩形
type Rectangle struct {Width, Height float64
}func (r Rectangle) Area() float64 {return r.Width * r.Height
}// 立方体
type Cube struct {Side float64
}func (c Cube) Area() float64 {return 6 * (c.Side * c.Side)
}func (c Cube) Volume() float64 {return c.Side * c.Side * c.Side
}func main() {var shapes []Shapeshapes = append(shapes, Rectangle{Width: 10, Height: 5})for _, shape := range shapes {fmt.Printf("Area: %.2f\n", shape.Area())}cube := Cube{Side: 3}fmt.Printf("Cube Area: %.2f, Volume: %.2f\n", cube.Area(), cube.Volume())
}

运行流程图

+---------------------+
|  计算形状面积      |
+---------------------+|
+----------+----------+
|                     |
|                     |
+                     +
|                     |
+--------+------------+
|  计算立方体体积    |
+---------------------+

2.5 依赖反转原则 (DIP)

定义:高层模块不应依赖于低层模块,二者应依赖于抽象(接口)。抽象不应依赖于细节,细节应依赖于抽象。

示例代码

package mainimport "fmt"// 数据库接口
type Database interface {Query() string
}// MySQL 数据库实现
type MySQL struct{}func (m MySQL) Query() string {return "Query from MySQL"
}// PostgreSQL 数据库实现
type PostgreSQL struct{}func (p PostgreSQL) Query() string {return "Query from PostgreSQL"
}// 数据库服务
type DatabaseService struct {db Database
}func (ds *DatabaseService) Execute() {fmt.Println(ds.db.Query())
}func main() {mysqlService := &DatabaseService{db: MySQL{}}mysqlService.Execute()  // 输出: Query from MySQLpostgresService := &DatabaseService{db: PostgreSQL{}}postgresService.Execute() // 输出: Query from PostgreSQL
}

运行流程图

+---------------------+
|  DatabaseService    |
+---------------------+|
+----------+----------+
|                     |
|                     |
+                     +
|                     |
+-------+-------------+
|  执行 Query 方法    |
+---------------------+

3. 架构设计的最佳实践

  • 模块化设计:将代码分为多个模块,每个模块负责特定功能,这提升了可读性和可维护性。
  • 高内聚低耦合:模块内部结构应保持高度一致性,而不同模块之间应保持低耦合,以便于代码的修改和重用。
  • 使用设计模式:设计模式有助于解决特定的架构问题,提升代码质量。
  • 自动化测试:通过单元测试和集成测试确保代码质量和系统可靠性。
  • 持续重构:在开发过程中保持代码质量,定期重构代码以适应新需求。

4. 示例代码的整体运行

以上代码展示了各种设计原则的实现方式。进行这些示例时,您可以在 Go 环境中逐一运行这些代码,并观察输出结果,帮助理解每个原则的应用。

代码的运行流程图展示了每个主要方法的调用路径,以及如何通过不同模块进行交互,体现了架构设计原则的有效性。

5. 运行流程图总结

每个示例中的运行流程图清晰地展示了不同组件之间的交互关系,帮助开发者理解各个设计原则如何有效整合,从而构成一个良好的软件架构。

6. 总结

熟练掌握架构设计原则是软件开发过程中的关键因素。这些原则不仅能够提升软件的质量和可维护性,同时也提高了团队的开发效率。通过实际案例的学习与实践,可以更好地理解和应用这些原则,为构建高质量的系统打下坚实的基础。


怎么样今天的内容还满意吗?再次感谢观众老爷的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hadoop生态圈框架部署(六)- HBase完全分布式部署

文章目录 前言一、Hbase完全分布式部署(手动部署)1. 下载Hbase2. 上传安装包3. 解压HBase安装包4. 配置HBase配置文件4.1 修改hbase-env.sh配置文件4.2 修改hbase-site.xml配置文件4.3 修改regionservers配置文件4.4 删除hbase中slf4j-reload4j-1.7.33.j…

108. UE5 GAS RPG 实现地图名称更新和加载关卡

在这一篇里,我们将实现对存档的删除功能,在删除时会有弹框确认。接着实现获取玩家的等级和地图名称和存档位置,我们可以通过存档进入游戏,玩家在游戏中可以在存档点存储存档。 实现删除存档 删除存档需要一个弹框确认&#xff0…

移除元素(leetcode 27)

给定一个数组,在数组中删除等于这个目标值的元素,然后返回新数组的大小 数组理论: 数组是一个连续的类型相近的元素的一个集合,数组上的删除是覆盖,只能由后面的元素进行覆盖,而不能进行真正意义上的地理位…

【征稿倒计时!华南理工大学主办 | IEEE出版 | EI检索稳定】2024智能机器人与自动控制国际学术会议 (IRAC 2024)

#华南理工大学主办!#IEEE出版!EI稳定检索!#组委阵容强大!IEEE Fellow、国家杰青等学术大咖领衔出席!#会议设置“优秀论文”“优秀青年学者报告”“优秀海报”等评优奖项 2024智能机器人与自动控制国际学术会议 &#…

【React】状态管理之Zustand

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 状态管理之Zustand引言1. Zustand 的核心特点1.1 简单直观的 API1.2 无需 Provi…

【ict基础软件赛道】真题-50%openGauss

题目取自赛前测试链接 OpenGauss安装前使用哪个工具检查环境是否符合安装哪个功能不是gs_guc工具提供的opengauss数据库逻辑复制的特点描述正确的是opengauss的全密态数据库等值查询能力描述正确的是哪个不属于ssh客户端工具opengauss三权分立说法正确的是opengauss wdr snapsh…

Python酷库之旅-第三方库Pandas(218)

目录 一、用法精讲 1021、pandas.DatetimeIndex.inferred_freq属性 1021-1、语法 1021-2、参数 1021-3、功能 1021-4、返回值 1021-5、说明 1021-6、用法 1021-6-1、数据准备 1021-6-2、代码示例 1021-6-3、结果输出 1022、pandas.DatetimeIndex.indexer_at_time方…

【miniMax开放平台-注册安全分析报告-无验证方式导致安全隐患】

前言 由于网站注册入口容易被机器执行自动化程序攻击,存在如下风险: 暴力破解密码,造成用户信息泄露,不符合国家等级保护的要求。短信盗刷带来的拒绝服务风险 ,造成用户无法登陆、注册,大量收到垃圾短信的…

树状数组+概率论,ABC380G - Another Shuffle Window

目录 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 二、解题报告 1、思路分析 2、复杂度 3、代码详解 一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 G - Another Shuffle Window 二、解题报告 1、思路分析 不难用树状数组计…

MySQL:表设计

表的设计 从需求中获得类,类对应到数据库中的实体,实体在数据库中表现为一张一张的表,类中的属性就对应着表中的字段(也就是表中的列) 表设计的三大范式: 在数据库设计中,三大范式&#xff0…

网盘聚合搜索项目Aipan(爱盼)

本文软件由网友 刘源 推荐; 简介 什么是 Aipan(爱盼) ? Aipan(爱盼)是一个基于 Vue 和 Nuxt.js 技术构建的开源网盘搜索项目。其主要目标是为用户提供一个能够自主拥有和管理的网盘搜索网站。该项目持续维护和更新&a…

当微软windows的记事本被AI加持

1985年,微软发布了Windows 1.0,推出了一款革命性的产品:记事本(Notepad)。这款软件旨在鼓励使用一种未来主义的新设备——鼠标,并让人们可以不依赖VI等键盘工具就能书写文本和编写代码。记事本因其简洁和高…

Dubbo 3.x源码(25)—Dubbo服务引用源码(8)notify订阅服务通知更新

基于Dubbo 3.1,详细介绍了Dubbo服务的发布与引用的源码。 此前我们学习了接口级的服务引入订阅的refreshInterfaceInvoker方法,当时还有最为关键的notify服务通知更新的部分源码没有学习,本次我们来学习notify通知本地服务更新的源码。 Dubb…

自存 关于RestController请求传参数 前端和后端相关

1.Get请求 Get请求传递参数一般是 1.通过PathVariable来映射 URL 绑定的占位符 后端 GetMapping("test/{id}")public R test(PathVariable Integer id){System.out.println(id);return R.success(id);}前端 export function test(id:any){return request({url:&q…

Python练习27

Python日常练习 题目: 编写函数,接收一个正偶数a,任何一个都可以分解成两个 素数之和,如果存在多组符合条件的素数,则全部输出。 例如: 【请输入一个正偶数】50 50 3 47 50 7 43 50 13 37 5…

查询DBA_FREE_SPACE缓慢问题

这个是一个常见的问题,理论上应该也算是一个bug,在oracle10g,到19c,我都曾经遇到过;今天在给两套新建的19C RAC添加监控脚本时,又发现了这个问题,在这里记录一下。 Symptoms 环境:…

已解决:spark代码中sqlContext.createDataframe空指针异常

这段代码是使用local模式运行spark代码。但是在获取了spark.sqlContext之后,用sqlContext将rdd算子转换为Dataframe的时候报错空指针异常 Exception in thread "main" org.apache.spark.sql.AnalysisException: java.lang.RuntimeException: java.lang.Nu…

20.UE5UI预构造,开始菜单,事件分发器

2-22 开始菜单、事件分发器、UI预构造_哔哩哔哩_bilibili 目录 1.UI预构造 2.开始菜单和开始关卡 2.1开始菜单 2.2开始关卡 2.3将开始菜单展示到开始关卡 3.事件分发器 1.UI预构造 如果我们直接再画布上设计我们的按钮,我们需要为每一个按钮进行编辑&#x…

每天五分钟机器学习:支持向量机算法数学基础之核函数

本文重点 从现在开始,我们将开启支持向量机算法的学习,不过在学习支持向量机算法之前,我们先来学习一些支持向量机所依赖的数学知识,这会帮助我们更加深刻的理解支持向量机算法,本文我们先来学习核函数。 定义 核函数(Kernel Function)是一种在支持向量机(SVM)、高…

向潜在安全信息和事件管理 SIEM 提供商提出的六个问题

收集和解读数据洞察以制定可用的解决方案是强大网络安全策略的基础。然而,组织正淹没在数据中,这使得这项任务变得复杂。 传统的安全信息和事件管理 ( SIEM ) 工具是组织尝试使用的一种方法,但由于成本、资源和可扩展性等几个原因&#xff0…