Go开源库、大项目的公共包,是这么用建造者模式的
建造者模式,也有翻译成生成器模式的,大家看到后知道他们是一个东西,都是Builer Pattern
翻译过来的就行。它是一种对象构建模式,是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 那么什么情况下适合使用建造模式呢?
- 当要构建的对象很大并且需要多个步骤时,使用构建器模式,有助于减小构造函数的大小。
我们先来看下其他语言里的 Builder,再看看 Go 怎么使用,进行个对比。
Java 的Builder
如果你是写过Java
程序一定对下面这类代码很熟悉。
Coffee.builder().name("Latti").price("30").build()
当然,自己给Coffee
类加上构建模式,还是需要写不少额外的代码,得给 Coffee 类加一个静态内部类 CoffeeBuilder,用CoffeeBuilder,去建造Coffee类的对象。
类、静态内部类傻傻分不清?可以看下小弟的 Java 文 光会面向对象基础做不了项目,还得掌握这些进阶知识
不过Java
里有一个lombok
包,只要引入这个包再在实体类加上@Builder
注解,就可以使用建造模式构建对象啦。
import lombok.Builder;
@Builder
public class Coffee extends BaseEntity implements Serializable {
private String name;
private Long price;
......
}
Go 里使用Builder
那在Go
里面要怎么实现Builder
模式呢?仿照上面这个模式,我们可以这样:
假设我们要在项目里搞个 DB 链接池,连接池提供了很多配置化的参数。
type DBPool struct {
dsn string
maxOpenConn int
maxIdleConn int
...
maxConnLifeTime time.Duration
}
我们给 DB 连接池加一个建造者模式,这样在设置每个配置化参数的时候就可以对参数进行一步检查,避免直接 new 连接池对象,再给每个属性赋值时都加判断,把每个参数的校验内聚到参数自己的建造者步骤里。
type DBPoolBuilder struct {
DBPool
err error
}
func Builder () *DBPoolBuilder {
b := new(DBPoolBuilder)
// 设置 DBPool 属性的默认值
b.DBPool.dsn = "127.0.0.1:3306"
b.DBPool.maxConnLifeTime = 1 * time.Second
b.DBPool.maxOpenConn = 30
return b
}
func (b *DBPoolBuilder) DSN(dsn string) *DBPoolBuilder {
if b.err != nil {
return b
}
if dsn == "" {
b.err = fmt.Errorf("invalid dsn, current is %s", dsn)
}
b.DBPool.dsn = dsn
return b
}
func (b *DBPoolBuilder) MaxOpenConn(connNum int) *DBPoolBuilder {
if b.err != nil {
return b
}
if connNum < 1 {
b.err = fmt.Errorf("invalid MaxOpenConn, current is %d", connNum)
}
b.DBPool.maxOpenConn = connNum
return b
}
func (b *DBPoolBuilder) MaxConnLifeTime(lifeTime time.Duration) *DBPoolBuilder {
if b.err != nil {
return b
}
if lifeTime < 1 * time.Second {
b.err = fmt.Errorf("connection max life time can not litte than 1 second, current is %v", lifeTime)
}
b.DBPool.maxConnLifeTime = lifeTime
return b
}
func (b *DBPoolBuilder) Build() (*DBPool, error) {
if b.err != nil {
return nil, b.err
}
if b.DBPool.maxOpenConn < b.DBPool.maxIdleConn {
return nil, fmt.Errorf("max total(%d) cannot < max idle(%d)", b.DBPool.maxOpenConn, b.DBPool.maxIdleConn)
}
return &b.DBPool, nil
}
本文的完整源码,已经同步收录到我整理的电子教程里啦,可向我的公众号「网管叨bi叨」发送关键字【设计模式】领取。
给公众号-网管叨bi叨,发送【设计模式】,领电子教程
接下来就可以使用构建模式创造DBPool
类型的对象了
package main
import "xxx/dbpool"
func main() {
dbPool, err := dbpool.Builder().DSN("localhost:3306").MaxOpenConn(50).MaxConnLifeTime(0 * time.Second).Build()
if err != nil {
fmt.Println(err)
}
fmt.Println(dbPool)
}
另外在建造者过程的每个参数步骤里,我们都借用了之前提到的处理 Go Error 的方式,把在外部调用时的错误判断,分散到了每个步骤里。
这么一来有从观感上觉得确实比定义一个参数巨多的 DBPool 构造函数要好一点。你觉得呢?
Go 里边还有一个函数时编程风格,利用的是函数的可变参数 (variadic parameters) ,这种编程模式就是 Option 模式,之前的文章 一些实用的编程模式--Options模式 里有提到过,可以比较一下。
总结
本文的完整源码,已经同步收录到我整理的电子教程里啦,可向我的公众号「网管叨bi叨」发送关键字【设计模式】领取,目前建造型的设计模式都已经更完,后面开始持续更新其他设计模式。
相关文章
- 彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-用户系统EP03
- go语言集成开发工具:GoLand 2022.2.1中文版「免账号登录」
- 17.Go语言-线程同步
- 【愚公系列】2022年08月 Go教学课程 032-结构体方法继承
- 你有对象类,我有结构体,Go lang1.18入门精炼教程,由白丁入鸿儒,go lang结构体(struct)的使用EP06
- 急如闪电快如风,彩虹女神跃长空,Go语言高性能Web框架Iris项目实战-初始化项目ep00
- 2022-08-01:以下go语言代码输出什么?A:panic;B:5;C:6;D:编译错误。
- [Go 夜读 第 139 期] Go 语言 Excelize 开源基础库介绍
- 理解真实项目中的 Go 并发 Bug
- 2023-02-24:请用go语言调用ffmpeg,解码mp4文件并保存为YUV420SP格式文件,采用YUV420P转YUV420SP的方式。
- 使用Go语言开发的云存储网盘项目开源哦
- Go 运行时:4 年之后
- 用Go重写Node.js服务:项目性能提升5倍,内存减少40%
- GO语言——IO项目
- Go项目优化——使用Elasticsearch搜索引擎
- Go-标准库-log(一)
- Go-包管理-go install
- go test命令(Go语言测试命令)完全攻略
- Linux上构建Go开发环境(linux安装go环境)
- 环境Go 编译 在 Linux 环境中的体验(go编译linux)
- 在 GitLab CI 中使用 Docker 构建 Go 项目
- Go语言链接Oracle数据库的实践记录(go 链接oracle)
- Go语言操作Oracle轻松实现数据库编程(go语言访问oracle)
- 语言Oracle中发挥神奇作用的Go语言(oracle中有go)
- Oracle Go用法快速指南(oracle go用法)