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

Go可以使用设计模式,但绝不是《设计模式》中的那样

文章精选推荐

1 JetBrains Ai assistant 编程工具让你的工作效率翻倍
2 Extra Icons:JetBrains IDE的图标增强神器
3 IDEA插件推荐-SequenceDiagram,自动生成时序图
4 BashSupport Pro 这个ides插件主要是用来干嘛的 ?
5 IDEA必装的插件:Spring Boot Helper的使用与功能特点
6 Ai assistant ,又是一个写代码神器
7 Cursor 设备ID修改器,你的Cursor又可以继续试用了

文章正文

Go语言是一门简洁、高效的编程语言,它支持面向对象编程的一些特性,比如接口、封装和组合,但并不直接提供类、继承等传统的面向对象概念。

因此,Go语言在使用设计模式时,有一些独特的方式和哲学,与传统面向对象语言(如 Java、C++)中的设计模式实现方式有所不同。

本文将深入探讨 Go 如何使用设计模式,并强调与《设计模式》中的传统实现的不同点,并通过代码示例进行说明。


1. Go 中的设计哲学

在 Go 中,有以下设计哲学与传统设计模式实现密切相关:

  • 组合优于继承:Go 提倡通过组合而不是继承来实现代码复用,避免了复杂的类层次结构。
  • 接口解耦:接口是 Go 语言中非常核心的特性,允许我们定义行为契约,而不依赖具体实现。
  • 简洁优先:Go 鼓励通过简单、直接的方式解决问题,而不是引入复杂的模式。

因此,在 Go 中,很多经典设计模式会简化,甚至在某些情况下,Go 原生特性(如接口、goroutine)已经能直接解决问题。


2. Go 中的常见设计模式解析

2.1 单例模式

传统实现
在面向对象语言中,单例模式通常需要通过私有构造函数、静态变量和双重检查锁定来实现线程安全的单例。

Go 实现
在 Go 中,可以通过 sync.Once 来实现线程安全的单例模式,代码更加简洁。

package mainimport ("fmt""sync"
)// 单例结构体
type Singleton struct{}var (instance *Singletononce     sync.Once
)// 获取单例实例
func GetInstance() *Singleton {once.Do(func() {instance = &Singleton{}})return instance
}func main() {s1 := GetInstance()s2 := GetInstance()fmt.Println(s1 == s2) // true
}

关键点

  • 使用 sync.Once 确保单例只初始化一次,避免手动实现锁和双重检查。

2.2 工厂模式

传统实现
在传统语言中,工厂模式通常通过一个基类(或接口)和具体子类实现。

Go 实现
由于 Go 语言没有类,工厂模式可以通过接口来抽象行为,通过函数直接创建实例。

package mainimport "fmt"// 动物接口
type Animal interface {Speak() string
}// 狗的实现
type Dog struct{}func (d Dog) Speak() string {return "Woof!"
}// 猫的实现
type Cat struct{}func (c Cat) Speak() string {return "Meow!"
}// 工厂函数
func NewAnimal(animalType string) Animal {switch animalType {case "dog":return Dog{}case "cat":return Cat{}default:return nil}
}func main() {dog := NewAnimal("dog")fmt.Println(dog.Speak()) // Woof!cat := NewAnimal("cat")fmt.Println(cat.Speak()) // Meow!
}

关键点

  • 使用简单的工厂函数代替复杂的类和构造函数。
  • 动物的行为通过接口抽象,而具体类型由工厂函数决定。

2.3 策略模式

传统实现
策略模式通常通过抽象基类和多个具体子类来实现不同策略。

Go 实现
在 Go 中,可以直接使用接口和函数作为策略实现。

package mainimport "fmt"// 策略接口
type PaymentStrategy interface {Pay(amount float64)
}// 信用卡支付
type CreditCard struct{}func (cc CreditCard) Pay(amount float64) {fmt.Printf("Paid %.2f using Credit Card.\n", amount)
}// PayPal 支付
type PayPal struct{}func (pp PayPal) Pay(amount float64) {fmt.Printf("Paid %.2f using PayPal.\n", amount)
}// 使用策略模式
func ProcessPayment(strategy PaymentStrategy, amount float64) {strategy.Pay(amount)
}func main() {cc := CreditCard{}pp := PayPal{}ProcessPayment(cc, 100.0) // Paid 100.00 using Credit Card.ProcessPayment(pp, 200.0) // Paid 200.00 using PayPal.
}

关键点

  • 使用接口定义策略行为,通过具体实现来提供不同的策略。
  • 策略选择可以在运行时动态更改。

2.4 观察者模式

传统实现
观察者模式通过一个主题(Subject)和多个观察者(Observer)实现,主题通知观察者更新。

Go 实现
在 Go 中,可以通过通道(channel)实现观察者模式,利用 goroutine 提供异步通知。

package mainimport "fmt"// 观察者
type Observer interface {Update(data string)
}// 具体观察者
type ConcreteObserver struct {id string
}func (co *ConcreteObserver) Update(data string) {fmt.Printf("Observer %s received: %s\n", co.id, data)
}// 主题
type Subject struct {observers []Observer
}func (s *Subject) Register(observer Observer) {s.observers = append(s.observers, observer)
}func (s *Subject) Notify(data string) {for _, observer := range s.observers {observer.Update(data)}
}func main() {subject := &Subject{}observer1 := &ConcreteObserver{id: "1"}observer2 := &ConcreteObserver{id: "2"}subject.Register(observer1)subject.Register(observer2)subject.Notify("Hello Observers!")
}

关键点

  • 使用接口定义观察者行为。
  • Notify 方法遍历所有观察者并调用其 Update 方法。

3. Go 的特色替代方案

在某些情况下,Go 的原生特性(如 goroutine、channel)可以替代传统设计模式。

3.1 使用 goroutine 替代命令模式

传统的命令模式通过封装请求和执行逻辑来解耦调用者和执行者。在 Go 中,可以直接通过 goroutine 和通道实现异步执行。

package mainimport "fmt"func main() {commandQueue := make(chan func(), 10)// 启动一个工作 goroutinego func() {for command := range commandQueue {command() // 执行命令}}()// 添加命令到队列commandQueue <- func() { fmt.Println("Command 1 executed") }commandQueue <- func() { fmt.Println("Command 2 executed") }close(commandQueue)
}

4. 总结

  • Go 的简单哲学:Go 通过接口、组合、goroutine 等特性,简化了很多传统设计模式的实现。
  • 减少复杂性:在 Go 中,我们可以直接使用函数、接口等轻量级工具来实现模式,而不是强依赖复杂的类和继承关系。
  • 场景驱动:Go 语言中的设计模式不是为了满足某种“模式理论”,而是为了适应具体的业务需求,强调代码的简洁和可读性。

Go 语言在使用设计模式时,更注重实践而不是形式。这种哲学让开发者能够专注于解决问题,而不是被复杂的模式实现所束缚。

相关文章:

Go可以使用设计模式,但绝不是《设计模式》中的那样

文章精选推荐 1 JetBrains Ai assistant 编程工具让你的工作效率翻倍 2 Extra Icons&#xff1a;JetBrains IDE的图标增强神器 3 IDEA插件推荐-SequenceDiagram&#xff0c;自动生成时序图 4 BashSupport Pro 这个ides插件主要是用来干嘛的 &#xff1f; 5 IDEA必装的插件&…...

【C语言】_使用冒泡排序模拟实现qsort函数

目录 1. 排序函数的参数 2. 排序函数函数体 2.1 比较元素的表示 2.2 交换函数Swap的实现 2.3 排序函数bubble_sort的实现 3. 测试整型数据排序 3.1 整型数据比较函数cmp_int的实现 3.2 整型数据排序后输出函数print_int的实现 3.3 整型数据测试函数test_int的实现 3…...

openCvSharp 计算机视觉图片找茬

一、安装包 <PackageReference Include"OpenCvSharp4" Version"4.10.0.20241108" /> <PackageReference Include"OpenCvSharp4.runtime.win" Version"4.10.0.20241108" /> 二、准备两张图片 三、编写代码 using OpenCv…...

从零开始开发纯血鸿蒙应用之处理外部文件

从零开始开发纯血鸿蒙应用 一、外部文件二、外部文件的访问形式1、主动访问2、被动访问 三、代码实现1、DocumentViewPicker2、Ability Skills3、onNewWant 函数4、冷启动时处理外部文件 一、外部文件 对于移动端app来说&#xff0c;什么是外部文件呢&#xff1f;是那些存储在…...

Spring中三级缓存详细讲解

1、Spring三级缓存是什么&#xff0c;过程是怎么样的&#xff1f; Spring 中的三级缓存主要用于单例 Bean 的生命周期管理&#xff0c;特别是在循环依赖时&#xff0c;它通过不同阶段暴露 Bean 实例来确保依赖注入的顺利完成。缓存的内容如下&#xff1a; 一级缓存 (singleton…...

论文阅读:《Whole-animal connectomes of both Caenorhabditis elegans sexes》

一 论文整体概述 论文下载链接&#xff1a;《Whole-animal connectomes of both Caenorhabditis elegans sexes》 补充信息和额外数据&#xff1a;https://www.nature.com/articles/s41586-019-1352-7 1. 作者期刊背景 该论文由Scott W. Emmons&#xff0c;David H. Hall等…...

嵌入式开发之STM32学习笔记day03

STM32之ADC&#xff08;模拟数字转换器&#xff09; 1 ADC简述2 ADC转换时间3 ADC转化结果存放机制4 ADC转化结果存放机制5 ADC电压转换 1 ADC简述 ADC&#xff08;Analog-Digital Converter&#xff09;模拟—数字转换器&#xff1b;ADC可以将引脚上连续变化的模拟电压转换为…...

windows10 安装 Golang 版本控制工具g与使用

下载包&#xff1a;https://github.com/voidint/g/releases 解压&#xff0c; 并添加到环境变量 g 常用命令 查询当前可供安装的stable状态及所有的 go 版本 # stable 版本 g ls-remote stable# 所有版本 g ls-remote安装目标 go 版本1.23.4g install 1.23.4切换到已安装的…...

SpringBoot 使用 Cache 集成 Redis做缓存保姆教程

1. 项目背景 Spring Cache是Spring框架提供的一个缓存抽象层&#xff0c;它简化了缓存的使用和管理。Spring Cache默认使用服务器内存&#xff0c;并无法控制缓存时长&#xff0c;查找缓存中的数据比较麻烦。 因此Spring Cache支持将缓存数据集成到各种缓存中间件中。本文已常…...

R数据分析:多分类问题预测模型的ROC做法及解释

有同学做了个多分类的预测模型,结局有三个类别,做的模型包括多分类逻辑回归、随机森林和决策树,多分类逻辑回归是用ROC曲线并报告AUC作为模型评估的,后面两种模型报告了混淆矩阵,审稿人就提出要统一模型评估指标。那么肯定是统一成ROC了,刚好借这个机会给大家讲讲ROC在多…...

数据结构与算法之二叉树: LeetCode 654. 最大二叉树 (Ts版)

最大二叉树 https://leetcode.cn/problems/maximum-binary-tree/ 描述 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值递归地在最大值 左边 的 子数组前缀上 构建左子树递归地在最大值…...

Linux 容器漏洞

定义&#xff1a;Linux 容器漏洞是指在容器技术&#xff08;如 Docker、LXC 等&#xff09;运行环境中存在的安全弱点。这些漏洞可能存在于容器镜像本身、容器运行时&#xff08;如 runc&#xff09;、容器编排工具&#xff08;如 Kubernetes&#xff09;或者容器与主机之间的交…...

file与io流(1)

-1- java.io.File类的使用 &#xff08;1&#xff09; 概述 File类及本章下的各种流&#xff0c;都定义在java.io包下。一个File对象代表硬盘或网络中可能存在的一个文件或者文件目录&#xff08;俗称文件夹&#xff09;&#xff0c;与平台无关。&#xff08;体会万事万物皆…...

忘记了PDF文件的密码,怎么办?

PDF文件可以加密&#xff0c;大家都不陌生&#xff0c;并且大家应该也都知道PDF文件有两种密码&#xff0c;一个打开密码、一个限制编辑密码&#xff0c;因为PDF文件设置了密码&#xff0c;那么打开、编辑PDF文件就会受到限制。忘记了PDF密码该如何解密&#xff1f; PDF和offi…...

Linux权限管理(用户和权限之间的关系)

Linux系列 文章目录 Linux系列一、Linux下用户类型二、普通权限的基本概念2.1、Linux中权限的类别2.2、Linux中权限对应的三种身份2.3、文件权限的标识 三、文件权限设置四、修改文件属主和属组4.1、chown修改文件的属主4.2、修改所属组 五、文件掩码六、目录权限 一、Linux下用…...

Python Selenium库入门使用,图文详细。附网页爬虫、web自动化操作等实战操作。

文章目录 前言1 创建conda环境安装Selenium库2 浏览器驱动下载&#xff08;以Chrome和Edge为例&#xff09;3 基础使用&#xff08;以Chrome为例演示&#xff09;3.1 与浏览器相关的操作3.1.1 打开/关闭浏览器3.1.2 访问指定域名的网页3.1.3 控制浏览器的窗口大小3.1.4 前进/后…...

【Uniapp-Vue3】使用defineExpose暴露子组件的属性及方法

如果我们想要让父组件访问到子组件中的变量和方法&#xff0c;就需要使用defineExpose暴露&#xff1a; defineExpose({ 变量 }) 子组件配置 父组件配置 父组件要通过onMounted获取到子组件的DOM 传递多个属性和方法 子组件 父组件...

【多模态LLM】英伟达NVLM多模态大模型训练细节和数据集

前期笔者介绍了OCR-free的多模态大模型&#xff0c;可以参考&#xff1a;【多模态&文档智能】OCR-free感知多模态大模型技术链路及训练数据细节&#xff0c;其更偏向于训练模型对于密集文本的感知能力。本文看一看英伟达出品的多模态大模型NVLM-1.0系列&#xff0c;虽然暂未…...

HTTP详解——HTTP基础

HTTP 基本概念 HTTP 是超文本传输协议 (HyperText Transfer Protocol) 超文本传输协议(HyperText Transfer Protocol) HTTP 是一个在计算机世界里专门在 两点 之间 传输 文字、图片、音视频等 超文本 数据的 约定和规范 1. 协议 约定和规范 2. 传输 两点之间传输&#xf…...

MySQL教程之:输入查询

如上一节所述&#xff0c;确保您已连接到服务器。这样做本身不会选择任何要使用的数据库&#xff0c;但没关系。在这一点上&#xff0c;了解一下如何发出查询比直接创建表、加载数据和从中检索数据更重要。本节介绍输入查询的基本原则&#xff0c;使用几个查询&#xff0c;您可…...

告别重复造轮子,用快马平台一键生成OpenClaw高效工具模块

最近在做一个机器人控制项目&#xff0c;需要集成OpenClaw机械爪模块。传统开发方式需要从零开始写大量重复代码&#xff0c;效率很低。后来尝试用InsCode(快马)平台生成核心模块&#xff0c;效果出乎意料的好。这里分享下具体实现思路和优化点&#xff1a; 安全初始化模块设计…...

Vue2项目实战:v-md-editor从安装到二次封装全流程(附常见问题解决)

Vue2项目深度整合v-md-editor&#xff1a;从核心配置到企业级封装实践 在内容管理系统的开发中&#xff0c;Markdown编辑器已成为技术文档、博客平台和知识库系统的标配组件。v-md-editor作为Vue生态下功能完备的Markdown解决方案&#xff0c;其双栏实时预览、深度定制能力和丰…...

百度智能云千帆AppBuilder API调用全攻略:从密钥获取到实战代码示例

百度智能云千帆AppBuilder API深度集成指南&#xff1a;从密钥管理到高效调用实践 在人工智能应用开发领域&#xff0c;快速集成可靠的AI能力已成为开发者提升效率的关键。百度智能云千帆AppBuilder作为一站式AI原生应用开发平台&#xff0c;其API接口的灵活调用能力让开发者能…...

如何用ContextMenuManager彻底掌控Windows右键菜单?4阶段优化法让操作效率提升300%

如何用ContextMenuManager彻底掌控Windows右键菜单&#xff1f;4阶段优化法让操作效率提升300% 【免费下载链接】ContextMenuManager &#x1f5b1;️ 纯粹的Windows右键菜单管理程序 项目地址: https://gitcode.com/gh_mirrors/co/ContextMenuManager Windows右键菜单是…...

​如何选择专业的液晶面板废气治理厂家

从智能手机到超高清大屏&#xff0c;液晶面板已成为信息时代不可或缺的核心组件。然而&#xff0c;在其精密制造过程中&#xff0c;光刻、显影、刻蚀等工序会产生大量成分复杂的有机废气、酸性气体及含尘废气。随着环保标准日益严格及面板厂产能不断扩张&#xff0c;【液晶面板…...

从数据孤岛到智能决策中枢:一体化系统如何重构 HR 数据流

去年某制造企业 HR 总监跟我抱怨&#xff1a;员工入职要在招聘系统录一遍信息&#xff0c;转正时人事系统再录一遍&#xff0c;发工资时薪酬系统又要重新核对。三个系统互不相通&#xff0c;一个员工的完整档案要从三个地方拼凑。这不是个例&#xff0c;而是很多企业正在经历的…...

KS-Downloader:快手无水印内容获取与管理的专业解决方案

KS-Downloader&#xff1a;快手无水印内容获取与管理的专业解决方案 【免费下载链接】KS-Downloader 快手&#xff08;KuaiShou&#xff09;视频/图片下载工具&#xff1b;数据采集工具 项目地址: https://gitcode.com/gh_mirrors/ks/KS-Downloader 在短视频内容创作与传…...

芯片设计Signoff前必看!数字后端工程师的5大验证避坑清单(含CTS实战案例)

芯片设计Signoff前必看&#xff01;数字后端工程师的5大验证避坑清单&#xff08;含CTS实战案例&#xff09; 在数字后端设计的最后冲刺阶段&#xff0c;每个工程师都经历过那种如履薄冰的体验——明明所有检查项都已通过&#xff0c;却在流片前夜发现某个角落的时序违例。这种…...

Windows DLL注入工具Xenos实战指南:问题解决与效能优化

Windows DLL注入工具Xenos实战指南&#xff1a;问题解决与效能优化 【免费下载链接】Xenos Windows dll injector 项目地址: https://gitcode.com/gh_mirrors/xe/Xenos 引言 在Windows系统开发与调试过程中&#xff0c;DLL注入技术扮演着重要角色&#xff0c;无论是插件…...

STEP3-VL-10B开源大模型部署:从HuggingFace下载到CSDN算力上线全过程

STEP3-VL-10B开源大模型部署&#xff1a;从HuggingFace下载到CSDN算力上线全过程 想体验一个能看懂图片、理解图表、甚至帮你分析复杂文档的AI助手吗&#xff1f;今天要介绍的STEP3-VL-10B&#xff0c;就是一个让你用普通显卡就能跑起来的“多面手”AI模型。 你可能听说过那些…...