广州好的做网站公司,智能云建站平台,陕西省建设厅网站ca验证失败,河南网站建设哪个公司做得好【Gin】精准应用#xff1a;Gin框架中工厂模式的现代软件开发策略与实施技巧(下) 大家好 我是寸铁#x1f44a; 【Gin】精准应用#xff1a;Gin框架中工厂模式的现代软件开发策略与实施技巧(下)✨ 喜欢的小伙伴可以点点关注 #x1f49d; 前言
本次文章分为上下两部分Gin框架中工厂模式的现代软件开发策略与实施技巧(下) 大家好 我是寸铁 【Gin】精准应用Gin框架中工厂模式的现代软件开发策略与实施技巧(下)✨ 喜欢的小伙伴可以点点关注 前言
本次文章分为上下两部分上部分为对理论的介绍下部分为具体的底层代码深度剖析和编程实践感兴趣的伙伴不要错过哦~
上篇【Gin】精准应用Gin框架中工厂模式的现代软件开发策略与实施技巧(上) 在现代软件开发中设计模式是提高代码质量和可维护性的重要工具之一。特别是对于像Gin这样的高性能、轻量级的Web框架如何合理运用设计模式显得尤为重要。工厂模式作为其中一种经典的创建型模式能够帮助开发者有效地解耦对象的创建过程并提供更大的灵活性和可扩展性。本文将深入探讨在Gin框架中工厂模式的具体应用场景、实施技巧以及现代软件开发中的最佳实践。 工厂模式通过引入工厂类来负责创建对象的过程可以根据需要动态地生成不同类型的对象而无需直接在代码中指定具体的类。在Gin框架中合理运用工厂模式可以优化路由、中间件和控制器的管理提升代码的模块化程度和可测试性。本文旨在帮助开发者深入理解工厂模式在实际项目中的应用以及如何利用它来构建更加灵活和可扩展的Web应用程序。 关键的类图和时序图
1 类图
角色介绍
Client: 客户端应用程序类它需要某种产品对象但不直接创建它们而是通过工厂来获取所需的产品对象。 GinFactory: 工厂接口或抽象类声明了创建产品对象的方法。它可以是抽象的也可以提供默认的实现但通常不会创建具体的产品对象。 RouterFactory: 具体工厂类实现了工厂接口或抽象类并负责创建具体的产品对象。每个具体工厂对应一种具体产品的创建方式。 IRoute: 产品接口或抽象类定义了工厂方法模式创建的对象类型。具体的产品类将实现这个接口或继承这个抽象类客户端最终会使用这些产品。 图1 工厂模式类图 由图1可知gin工厂类具有创建gin引擎对象的方法实现IRoute接口具体的创建对象职责由不同的Router路由工厂类承担。 2 时序图
图2 工厂模式时序图 由图2得客户端请求产品客户端Client需要获取具体产品invoke()调用工厂对象的方法来请求产品对象。 工厂方法调用工厂对象Gin接收到客户端的请求调用工厂方法Default()来创建具体产品。 具体工厂创建产品具体工厂类Router实现了工厂方法根据客户端请求创建具体的产品对象New()。 产品创建完成具体产品IRoute被创建并返回给客户端客户端可以继续使用这个产品实例进行操作。 主程序的流程
由如下图3可得 程序开始 先调用Gin工厂的Defalut()获得engine引擎对象其中Defalut()方法中包含Router工厂的真正创建对象方法New() 返回创建好的engine引擎对象返回对象后客户端获取到engine对象程序结束。 图 3 工厂模式主程序流程图
程序模块之间的调用关系
如下图展示程序模块之间的调用关系 图4 工厂模式调用关系图 由图4得: 客户端调用gin工厂,gin工厂的gin.Default()创建一个默认的Gin引擎对象Default()方法中调用New()创建engine对象实例engine对象的类型为Engine,New()方法中用{}的方式创建Engine结构体对象对象创建完毕后再把对象返回给客户端使用。 在上图的基础上下面结合设计模式对程序中各个模块的源码进行深入剖析 图5 客户端调用代码 首先在客户端中使用gin工厂调用Defalut()方法得到一个Gin引擎对象。这里无需暴露任何的new创建对象gin.Default() 可以被看作是一个工厂方法它封装了创建Gin引擎实例的细节。客户端代码即这段示例中的 main() 函数不需要了解或直接处理Gin引擎的内部实现细节。通过调用 gin.Default()客户端只需获取一个已经配置好的Gin引擎实例然后可以直接开始定义路由和处理HTTP请求。 图6 抽象工厂代码 该代码的位置位于gin.go文件中的220-226行需要注意的是在Golang的世界中并没有 abstract 关键字。Go语言支持面向对象的设计哲学之一是保持简洁和直接因此它没有类似于其他面向对象语言如Java、C#中的抽象类和抽象方法的概念。并且所有的成员都封装在具体的Struct中可以类比为Java的类但与Java不同的是Struct不存放具体的方法只是将要用到的成员变量封装到一个结构体Struct中只承担存储的职责无任何实际的操作。实际的操作只在文件中的方法中具体编写、展开即可。为了比较好理解设计模式关系可以暂且认为Default()为抽象工厂部分具体的实现New为具体工厂部分。 工厂方法的定义在Default()函数内部首先调用了 New() 函数来创建一个新的 Engine 实例。这里可以将 New() 函数视为简单工厂方法用于实例化一个基本的 Engine 对象。 封装对象创建过程接着通过 engine.Use(Logger(), Recovery()) 将日志记录和恢复中间件附加到新创建的引擎实例上。这一步是在工厂方法内部对对象进行配置的典型操作确保了每个通过 Default() 创建的引擎都具有相同的预配置行为。 配置默认选项Default() 方法通过接受可选的 OptionFunc 参数来支持对引擎的额外定制。这些选项可以是函数或者闭包允许开发者在创建引擎时进一步配置和调整其行为例如设置路由、中间件或者其他定制化的功能。 灵活的选项扩展Default() 方法通过接受可选的 OptionFunc 参数来支持对引擎的额外定制。这些选项可以是函数或者闭包允许开发者在创建引擎时进一步配置和调整其行为例如设置路由、中间件或者其他定制化的功能。 隐藏具体实现细节 客户端调用 Default() 方法时只需知道它返回一个预配置好的 Engine 实例而无需了解内部的对象创建和配置细节。这种封装隐藏了具体实现降低了客户端代码与Gin框架的耦合度同时提升了代码的可维护性和灵活性。 小结Default() 函数在这段代码中充当了工厂方法的角色通过封装对象的创建和配置过程提供了一个统一的接口来获取预配置的 Engine 实例。这种设计符合工厂模式的核心思想即封装和隐藏对象的创建细节提供灵活性和可扩展性的同时简化了客户端代码的使用方式。 图7 具体工厂代码 该代码的位置位于gin.go文件中的188-218行由于没有抽象类和具体类的概念这里可以将New()具体实现部分作为具体工厂角色。下面对具体工厂的职责和对象的初始化代码进行剖析 图8 New方法代码 189行debugPrintWARNINGNew()这是一个调试函数或者日志函数的调用用于输出或记录关于 New() 函数被调用的警告信息或日志。它通常用于开发和调试阶段帮助开发人员跟踪函数的调用流程。 图9 定义Engine对象 191-195行engine : Engine{ … }创建一个名为 engine 的新的 Engine 结构体实例。在这里使用结构体字面量初始化了 Engine 和 RouterGroup 结构体的字段。Engine 结构体可能包含了整个应用程序的路由、中间件和其他配置信息。 图10 结构体字段代码 196-212行 Engine 结构体的字段初始化 FuncMap模板函数映射初始化为空。 RedirectTrailingSlash是否重定向尾部斜杠默认为 true。 RedirectFixedPath是否重定向固定路径默认为 false。 HandleMethodNotAllowed是否处理不允许的方法默认为 false。 ForwardedByClientIP是否使用客户端IP地址默认为 true。 RemoteIPHeaders远程IP地址的请求头字段默认为 [“X-Forwarded-For”, “X-Real-IP”]。 TrustedPlatform受信任的平台默认为 defaultPlatform。 UseRawPath是否使用原始路径默认为 false。 RemoveExtraSlash是否移除额外的斜杠默认为 false。 UnescapePathValues是否解码路径中的值默认为 true。 MaxMultipartMemory多部分表单的最大内存默认为 defaultMultipartMemory。 trees方法树的初始化使用 make 函数创建一个容量为 9 的空切片。 delims渲染模板的分隔符默认左右分隔符为 {{ 和 }}。 secureJSONPrefix安全的 JSON 前缀默认为 “while(1);”。 trustedProxies受信任的代理服务器列表默认为 [“0.0.0.0/0”, “::/0”]。 trustedCIDRs受信任的CIDR列表默认为 defaultTrustedCIDRs。 图11 engine方法代码 213行 engine.RouterGroup.engine engine将当前创建的 engine 实例赋给 RouterGroup 结构体中的 engine 字段。这个步骤确保 RouterGroup 中可以访问到当前的 engine 实例。 214-216行engine.pool.New func() any { … }定义了 pool 结构体中 New 字段的函数回调。这个函数会在需要时创建新的上下文对象。具体来说它通过调用 engine.allocateContext(engine.maxParams) 来创建一个新的上下文对象。这种设计通常用于对象池技术用于重用对象并减少内存分配的开销。 217-218行return engine.With(opts…)最后调用 With() 方法并传入 opts… 参数列表中的配置选项对 engine 进行最后的配置。这里假设 With() 方法用于应用外部传入的配置选项返回一个完全配置好的 Engine 实例。 图12 engine结构体代码 图13 engine结构体代码 89-176行Engine结构体的字段说明如下(省略部分为注释) RouterGroup嵌入了一个 RouterGroup 结构体表示 Engine 结构体包含了 RouterGroup 的属性和方法。 RedirectTrailingSlash bool布尔类型的属性 RedirectTrailingSlash用于控制是否重定向尾部斜杠。 RedirectFixedPath bool布尔类型的属性 RedirectFixedPath用于控制是否重定向固定路径。 HandleMethodNotAllowed bool布尔类型的属性 HandleMethodNotAllowed用于控制是否处理不允许的方法。 ForwardedByClientIP bool布尔类型的属性 ForwardedByClientIP用于控制是否通过客户端IP进行转发。 AppEngine bool布尔类型的属性 AppEngine表示是否是 AppEngine。 UseRawPath bool布尔类型的属性 UseRawPath用于控制是否使用原始路径。 UnescapePathValues bool布尔类型的属性 UnescapePathValues用于控制是否解码路径值。 RemoveExtraSlash bool布尔类型的属性 RemoveExtraSlash用于控制是否移除额外的斜杠。 RemoteIPHeaders []string字符串数组类型的属性 RemoteIPHeaders存储远程IP的头部信息。 TrustedPlatform string字符串类型的属性 TrustedPlatform存储受信任的平台。 MaxMultipartMemory int64int64 类型的属性 MaxMultipartMemory表示最大的多部分内存大小。 UseH2C bool布尔类型的属性 UseH2C表示是否使用 H2C。 ContextWithFallback bool布尔类型的属性 ContextWithFallback用于控制是否使用后备上下文。 delims render.Delimsrender.Delims 类型的属性 delims存储渲染分隔符。 secureJSONPrefix string字符串类型的属性 secureJSONPrefix存储安全JSON的前缀。 HTMLRender render.HTMLRenderHTMLRender 类型的属性 HTMLRender表示HTML渲染器。 FuncMap template.FuncMaptemplate.FuncMap 类型的属性 FuncMap存储函数映射。 allNoRoute HandlersChainHandlersChain 类型的属性 allNoRoute表示所有没有路由的处理程序链。 allNoMethod HandlersChainHandlersChain 类型的属性 allNoMethod表示所有没有方法的处理程序链。 noRoute HandlersChainHandlersChain 类型的属性 noRoute表示没有路由的处理程序链。 noMethod HandlersChainHandlersChain 类型的属性 noMethod表示没有方法的处理程序链。 pool sync.Poolsync.Pool 类型的属性 pool表示同步池。 trees methodTreesmethodTrees 类型的属性 trees表示方法树。 maxParams uint16uint16 类型的属性 maxParams表示最大参数数量。 maxSections uint16uint16 类型的属性 maxSections表示最大节段数量。 trustedProxies []string字符串数组类型的属性 trustedProxies存储受信任的代理。 trustedCIDRs []*net.IPNetnet.IPNet 类型的指针数组属性 trustedCIDRs存储受信任的CIDR网段。 案例及调试分析
测试案例
package mainimport (github.com/gin-gonic/ginnet/http
)// 定义一个结构体来封装 Gin 框架相关的操作
type Server struct {router *gin.Engine
}// 初始化 Server 结构体对象
func GetServer() *Server {return Server{router: gin.Default(),}
}// Gin引擎对象调用setupRoutes函数,设置路由处理。
func (s *Server) setupRoutes() {s.router.GET(/, func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{message: Hello, welcome to the Factory demo!,})})
}// 启动 HTTP 服务器
func (s *Server) runServer(addr string) error {return s.router.Run(addr)
}func main() {server : GetServer()server.setupRoutes()err : server.runServer(:8080)if err ! nil {panic(err)}
} 工厂模式案例详细说明如下 图82 定义的结构体信息 Server 结构体用来封装 Gin 框架的相关操作其中包括一个 router 字段类型为 *gin.Engine即 Gin 框架的核心引擎。 图83 获得Server的方法 GetServer是一个工厂方法用来创建并初始化 Server 结构体的实例。在这里它返回一个新的 Server 实例并通过gin.Default()方法创建一个默认配置的 Gin 引擎并将其赋值给 router 字段。 图84 设置路由的方法 setupRoute方法用于设置 HTTP 请求的路由处理函数。在这里它定义了一个 GET 请求的处理函数当用户访问根路径 “/” 时返回一个 JSON 响应内容为 {message: Hello, welcome to the Factory demo!}。 图85 启动HTTP服务器的方法 runServer 方法用于启动 HTTP 服务器监听指定的地址addr 参数。它调用了 Gin 框架的 Run 方法来启动 HTTP 服务器并返回可能出现的错误error。 图86 客户端主方法 main 函数是程序的入口点。在 main 函数中首先使用 GetServer 方法创建了一个 Server 实例。然后调用 setupRoutes 方法设置了 HTTP 请求的路由处理函数。最后调用runServer方法启动 HTTP 服务器监听 8080 端口。如果启动过程中发生错误通过panic函数处理并输出错误信息。 调试分析如下Gin引擎对象启动成功正在监听8080端口Demo启动成功 图87 工厂模式调试成功图 测试结果 服务端监听8080端口并往客户端的端口发送一条Get类型的Json请求信息。工厂模式测试成功 图127 服务端监听8080端口 图128 获取服务端的响应信息 结语 通过本文的探讨我们深入了解了工厂模式在现代软件开发中的关键作用和实际应用。工厂模式不仅提供了一种灵活的对象创建机制还能有效地管理复杂系统中的对象依赖关系。无论是简单工厂、工厂方法还是抽象工厂模式它们都为开发者提供了多种选择以应对不同的设计需求和业务场景。在未来的软件开发中结合工厂模式的设计思想将有助于构建更加稳健、可维护和可扩展的应用程序。 注本次文章分为上下两部分上部分为对理论的介绍下部分为具体的底层代码深度剖析和编程实践感兴趣的伙伴不要错过哦~ 看到这里的小伙伴恭喜你又掌握了一个技能 希望大家能取得胜利坚持就是胜利 我是寸铁我们下期再见 往期好文
保姆级教程
【保姆级教程】Windows11下go-zero的etcd安装与初步使用
【保姆级教程】Windows11安装go-zero代码生成工具goctl、protoc、go-zero
【Go-Zero】手把手带你在goland中创建api文件并设置高亮 报错解决
【Go-Zero】Error: user.api 27:9 syntax error: expected ‘:‘ | ‘IDENT‘ | ‘INT‘, got ‘(‘ 报错解决方案及api路由注意事项
【Go-Zero】Error: only one service expected goctl一键转换生成rpc服务错误解决方案
【Go-Zero】【error】 failed to initialize database, got error Error 1045 (28000):报错解决方案
【Go-Zero】Error 1045 (28000): Access denied for user ‘root‘‘localhost‘ (using password: YES)报错解决方案
【Go-Zero】type mismatch for field “Auth.AccessSecret“, expect “string“, actual “number“报错解决方案
【Go-Zero】Error: user.api 30:2 syntax error: expected ‘)‘ | ‘KEY‘, got ‘IDENT‘报错解决方案
【Go-Zero】Windows启动rpc服务报错panic:context deadline exceeded解决方案 Go面试向
【Go面试向】defer与time.sleep初探
【Go面试向】defer与return的执行顺序初探
【Go面试向】Go程序的执行顺序
【Go面试向】rune和byte类型的认识与使用
【Go面试向】实现map稳定的有序遍历的方式