设计模式(Golang)

一、设计原则

软件设计原则是一组指导软件开发人员进行系统设计、模块划分、类和接口定义、代码组织等方面的准则,旨在提高软件的可维护性、可扩展性、灵活性和重用性。以下是软件设计领域中广泛认可的一些核心原则:

1. 开闭原则 (Open-Closed Principle, OCP)

开放(Open):对扩展开放,即允许在不修改现有代码的基础上扩展系统的行为或功能。这意味着应通过扩展而非修改已有类或模块来应对需求变化。

封闭(Closed):对修改封闭,即已有的代码(尤其是稳定的部分)应尽量避免改动。这通常通过抽象和依赖注入来实现,使系统能够在不改动现有代码的情况下添加新功能或适应新情况。

2. 单一职责原则 (Single Responsibility Principle, SRP)

一个类、模块或函数应有且仅有一个引起它变化的原因。换句话说,每个类或模块应专注于一个特定的职责或功能领域,避免承担过多责任。这样有助于保持代码的高内聚性和低耦合性,使得代码更易于理解和测试。

3. 里氏替换原则 (Liskov Substitution Principle, LSP)

子类对象应当能够替换其基类对象出现在任何位置,且不会导致程序的正确性受到影响。这意味着子类必须遵守基类的约定,且不应破坏基类的行为。LSP 强调了继承层次中行为的兼容性,是实现多态和代码复用的重要基础。

4. 依赖倒置原则 (Dependency Inversion Principle, DIP)

高层模块不应依赖于低层模块,两者都应依赖于抽象(接口或抽象类)。具体而言:

  • 高层模块(政策制定者)定义抽象。
  • 低层模块(策略实现者)实现抽象。
  • 抽象不应依赖于细节,细节(具体实现)应依赖于抽象。

DIP 促进了模块间的解耦,使得代码更容易适应变化,同时鼓励面向接口编程。

5. 接口隔离原则 (Interface Segregation Principle, ISP)

客户端不应该被迫依赖它不需要的接口方法。一个大而全的接口应该拆分为多个更小、更专注的接口,每个接口只包含客户端实际需要的方法。ISP 避免了胖接口带来的冗余和耦合,使接口更易于理解和使用。

6. 迪米特法则 (Law of Demeter, LoD) 或最少知识原则 (Least Knowledge Principle)

一个对象应当对其他对象有最少的了解。也就是说,一个对象应尽量减少与其他对象的直接交互,只与“朋友”(直接关联的对象)交谈。迪米特法则有助于减少系统的耦合度,提高模块间的独立性。

7. 合成复用原则 (Composite Reuse Principle, CRP)

优先使用对象组合(has-a 或 contains-a 关系)而不是类继承(is-a 关系)来实现复用。继承在某些场景下是有用的,但它可能导致紧耦合和脆弱的基类。合成则提供了更灵活的结构,允许在运行时动态地改变对象间的协作关系。

应用原则的注意事项

  • 原则之间存在关联:在实际应用中,这些原则往往相互交织,共同指导设计决策。
  • 权衡与折衷:没有绝对的最佳实践,不同原则在特定场景下可能需要权衡取舍。
  • 具体情况具体分析:原则是指导而非教条,应根据项目的具体需求、技术栈、团队习惯等因素灵活运用。

遵循这些软件设计原则,有助于构建出更加健壮、易于维护和扩展的软件系统。设计时应综合考虑这些原则,并结合具体的项目背景和团队共识,做出最适合当前项目的决策。

二、设计模式

创建型模式

工厂模式

目的:提供一个创建对象的统一接口,隐藏对象的具体创建过程。

Go 实现:使用函数或方法返回特定接口类型的实例,根据输入参数或其他条件选择创建不同类型的对象。

type Product interface {Operation()
}type ConcreteProductA struct{}
func (p *ConcreteProductA) Operation() {}type ConcreteProductB struct{}
func (p *ConcreteProductB) Operation() {}func Factory(productType string) Product {switch productType {case "A":return &ConcreteProductA{}case "B":return &ConcreteProductB{}default:panic("Unknown product type")}
}// 使用
product := Factory("A")
product.Operation()
单例模式

目的:确保一个类只有一个实例,并提供一个全局访问点。

Go 实现:利用 sync.Once 和全局变量确保单例对象只被初始化一次。

import "sync"type Singleton struct{}var (instance *Singletononce     sync.Once
)func GetInstance() *Singleton {once.Do(func() {instance = &Singleton{}})return instance
}
建造者模式

目的:将复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。

Go 实现:定义一个 Builder 接口,实现多个具体的 Builder 类型,客户端通过调用 Builder 的方法逐步构造对象,最后调用 Build 方法得到完整对象。

type Vehicle interface {Describe() string
}type CarBuilder struct {wheels   intdoors    intcolor    stringengine   string
}func (cb *CarBuilder) SetWheels(wheels int)   { cb.wheels = wheels }
func (cb *CarBuilder) SetDoors(doors int)     { cb.doors = doors }
func (cb *CarBuilder) SetColor(color string)  { cb.color = color }
func (cb *CarBuilder) SetEngine(engine string) { cb.engine = engine }func (cb *CarBuilder) Build() Vehicle {return &Car{wheels:   cb.wheels,doors:    cb.doors,color:    cb.color,engine:   cb.engine,}
}type Car struct {wheels   intdoors    intcolor    stringengine   string
}func (c *Car) Describe() string {return fmt.Sprintf("Car with %d wheels, %d doors, color %s, engine %s",c.wheels, c.doors, c.color, c.engine)
}// 使用
builder := &CarBuilder{}
builder.SetWheels(4).SetColor("Red").SetEngine("V6")
vehicle := builder.Build()
vehicle.Describe()

结构型模式

适配器模式

目的:将一个类的接口转换成客户希望的另一个接口,使得原本不兼容的类可以一起工作。

Go 实现:创建一个新的类型,该类型包含了需要适配的类型,并实现目标接口。

type Target interface {Request()
}type Adaptee struct{}func (a *Adaptee) SpecificRequest() {}type Adapter struct {adaptee *Adaptee
}func (a *Adapter) Request() {a.adaptee.SpecificRequest()
}// 客户端代码使用 Target 接口,无需知道 Adapter 内部使用了 Adaptee
装饰者模式

目的:动态地给对象添加额外的责任或行为。

Go 实现:通过组合(包含)原对象,创建装饰者对象,并在装饰者中扩展或修改原对象的行为。

type Component interface {Operation() string
}type ConcreteComponent struct{}func (cc *ConcreteComponent) Operation() string {return "ConcreteComponent.Operation()"
}type Decorator struct {component Component
}func (d *Decorator) Operation() string {return d.component.Operation()
}type ConcreteDecoratorA struct {Decorator
}func (cd *ConcreteDecoratorA) Operation() string {originalOp := cd.Decorator.Operation()return fmt.Sprintf("ConcreteDecoratorA.Operation() -> %s", originalOp)
}// 使用
component := &ConcreteComponent{}
decorated := &ConcreteDecoratorA{Decorator: Decorator{component: component}}
fmt.Println(decorated.Operation())

行为型模式

观察者模式

目的:定义对象间一对多的依赖关系,当一个对象状态改变时,所有依赖于它的对象都会收到通知并自动更新。

Go 实现:使用 channels 和 goroutines 实现异步通知,或利用 sync.Cond 实现同步通知。

type Subject interface {Register(Observer)Unregister(Observer)NotifyObservers()
}type ConcreteSubject struct {observers []Observerstate     string
}func (s *ConcreteSubject) Register(o Observer) {s.observers = append(s.observers, o)
}func (s *ConcreteSubject) Unregister(o Observer) {// ...
}func (s *ConcreteSubject) NotifyObservers() {for _, observer := range s.observers {go observer.Update(s.state)}
}type Observer interface {Update(state string)
}// 实现 Observer 接口的具体观察者
策略模式

目的:定义一系列算法,并将每个算法封装为一个单独的类,使得算法可以在运行时进行切换。

Go 实现:定义一个接口(策略),实现多个具体的策略类型,客户端根据需要选择并传递合适的策略对象。

type Strategy interface {Calculate(numbers []int) int
}type AddStrategy struct{}func (as *AddStrategy) Calculate(numbers []int) int {sum := 0for _, n := range numbers {sum += n}return sum
}type MultiplyStrategy struct{}func (ms *MultiplyStrategy) Calculate(numbers []int) int {product := 1for _, n := range numbers {product *= n}return product
}func Process(numbers []int, strategy Strategy) int {return strategy.Calculate(numbers)
}// 使用
result := Process([]int{1, 2, 3}, &AddStrategy{})
fmt.Println(result)  // 输出 6result = Process([]int{1, 2, 3}, &MultiplyStrategy{})
fmt.Println(result)  // 输出 6

其他模式

除了上述示例,Go 语言中还可以实现诸如模板方法模式、命令模式、迭代器模式、中介者模式、备忘录模式、解释器模式、状态模式、访问者模式、责任链模式等。在应用设计模式时,应遵循设计原则,结合 Go 语言的特性(如接口、并发模型等),并根据具体需求进行调整和创新。

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

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

相关文章

25. 【Android教程】列表控件 ListView

在学习了 ScrollView 及 Adapter 两节内容之后,大家应该对 ListView 有了一些基本的了解,它是一个列表样式的 ViewGroup,将若干 item 按行排列。ListView 是一个很基本的控件也是 Android 中最重要的控件之一。它可以帮助我们完成多个 View 的…

字典树(Trie树)详解

字典树(Trie树)详解 理论模块: trie 树 字典树是一种用于实现字符串快速检索的多叉树结构 trie 的每个节点都拥有若干个字符指针,若在插入或检索字符串时扫描到一个字符 c c c 就沿着当前节点的 c c c 字符指针&#xff0c…

【Qt 学习笔记】QWidget的windowOpacity属性 | cursor属性 | font属性

博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ QWidget的windowOpacity属性 | cursor属性 | font属性 文章编号&#…

leetcode hot100_day20

4/14/2024 128.最长连续序列 自己的 这是前两天做一半的题目了。这题给我的教训就是用哈希表的时候一定一定要考虑重复元素的问题!!!! 这题让我想到了最长递增子序列,只是名字有点像。子序列和子数组还不一样一个连续…

算法练习第18天|111.二叉树的最小深度

111.二叉树的最小深度 111. 二叉树的最小深度 - 力扣(LeetCode)https://leetcode.cn/problems/minimum-depth-of-binary-tree/description/ 题目描述: 给定一个二叉树,找出其最小深度。 最小深度是从根节点到最近叶子节点的最…

Unity 左右折叠显示与隐藏UI的简单实现

要实现一个简单的UI左右折叠显示与隐藏,可以结合遮罩,通过代码控制UI区块的宽度和位移来实现。 具体可以按以下步骤实现: 1、新建一个Image组件,并添加精灵,调整大小后,复制一份作为该UI的父物体&#xf…

CANoe中LIN工程主节点的配置(如何切换调度表)

1:前置条件 1)工程已经建立,simulation窗口已经配置好(包括且不限于通道mappin好,数据库文件已经添加) 2)我已系统自带sampleCfg工程,作为例子。如下图 2 :主节点的配置…

边缘计算网关主要有哪些功能?-天拓四方

随着物联网(IoT)的快速发展和普及,边缘计算网关已经成为了数据处理和传输的重要枢纽。作为一种集成数据采集、协议转换、数据处理、数据聚合和远程控制等多种功能的设备,边缘计算网关在降低网络延迟、提高数据处理效率以及减轻云数…

基于51单片机的温度控制恒温箱设计—数码管显示

基于51单片机的温度控制恒温箱 (仿真+程序+原理图+PCB+设计报告) 功能介绍 具体功能: 1.DS18B20温度传感器测温; 2.数码管实时显示温度; 3.按键设置温度上下限阈值&am…

Spring Boot 统一功能处理(二)

本篇主要介绍Spring Boot统一功能处理中的统一数据返回格式。 目录 一、定义统一的返回类 二、配置统一数据格式 三、测试配置效果 四、统一格式返回的优点 五、源码角度解析String问题 一、定义统一的返回类 在我们的接口在处理请求时,返回的结果可以说是参…

【CAN】采样点介绍及测试方法

文章目录 1 什么是采样点2 为什么需要采样点3 采样点的计算公式4 VH6501测试原理和方法4.1 VH6501测试采样点原理4.2 VH6501测试方法 >>返回总目录<< 1 什么是采样点 采样点是节点判断信号逻辑电平的位置&#xff0c;是CAN控制器读取总线电平&#xff0c;并解释各…

【Git教程】(十二)工作流之项目设置 — 何时使用工作流,工作流的结构,项目设置概述、执行过程及其实现 ~

Git教程 工作流之项目设置 1️⃣ 何时使用工作流2️⃣ 工作流的结构3️⃣ 概述4️⃣ 使用要求5️⃣ 执行过程及其实现5.1 基于项目目录创建一个新的版本库5.2 以文件访问的方式共享版本库5.3 用 Git daemon 来共享版本库5.4 用 HTTP 协议来共享版本库5.5 用 SSH 协议来共享版…

【论文阅读02】一种基于双通道的水下图像增强卷积神经网络

来源&#xff1a;海洋论坛▏一种基于双通道的水下图像增强卷积神经网络 当前不会的 一、背景&#xff1a; 水下图像增强方法包含有无水下成像模型的水下图像增强方法、基于水下成像模型的水下图像恢复方法、水下成像模型与深度学习相结合的方法以及完全采用深度学习的方…

基于Python的景区票务人脸识别系统(V2.0)

博主介绍&#xff1a;✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3…

数据结构速成--数据结构和算法

由于是速成专题&#xff0c;因此内容不会十分全面&#xff0c;只会涵盖考试重点&#xff0c;各学校课程要求不同 &#xff0c;大家可以按照考纲复习&#xff0c;不全面的内容&#xff0c;可以看一下小编主页数据结构初阶的内容&#xff0c;找到对应专题详细学习一下。 目录 一…

【Linux】磁盘阵列RAID技术

目录 一、RAID介绍 1.1 什么是RAID技术&#xff1f; 1.2 为什么要使用RAID技术&#xff1f; 二、RAID级别 2.1 常见的RAID级别 2.2 常见RAID介绍 三、RAID特性对比 一、RAID介绍 1.1 什么是RAID技术&#xff1f; 把多块独立的物理磁盘按不同的方式组合起来形成一个硬盘…

【ENSP】华为三层交换机配置AAA认证,开启telnet服务

配置步骤 1.给交换机配置ip地址&#xff0c;以便登陆 2.配置AAA&#xff0c;用户名&#xff0c;密码&#xff0c;服务类型&#xff0c;用户权限 3.配置接入设备的数量 4.开启telnet服务 LSW2交换机配置 u t m #关闭提示 sys …

基于单链表实现通讯管理系统!(有完整源码!)

​ 个人主页&#xff1a;秋风起&#xff0c;再归来~ 文章专栏&#xff1a;C语言实战项目 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01; 1、前言 友友们&#xff0c;这篇文章是基于单链…

使用Python模仿文件行为

在Python中&#xff0c;你可以通过文件操作函数&#xff08;如open()函数&#xff09;以及模拟输入输出流的库&#xff08;如io模块&#xff09;来模拟文件行为。下面是一些示例&#xff0c;展示了如何使用这些工具在Python中模拟文件行为。 1、问题背景 在编写一个脚本时&…