一起学习 Go 语言设计模式之建造者模式(下)

简介: 在设计模式中,建造者模式就是解决如何将这些部件组装成一辆完整的汽车并返回给用户的设计模式。建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品。

Go 代码示例

代码组织结构如下:


image.png


  1. 首先创建 house.go 文件, 建立 House 这个产品基类,代码如下;
package main
type House struct {
  windowType string
  doorType   string
  swimPool   string
  floor      int
}


正像前文所说一眼,房子有窗户、门、游泳池、楼层等部分组成。


  1. 然后创建抽象创建者 iBuilder.go 文件,也是我们的建造者接口,分别定义 4 个 set  和 1 个 getHouse()  方法,代码如下:
package main
type IBuilder interface {
  setWindowType()
  setDoorType()
  setNumFloor()
  setSwimPool()
  getHouse() House
}
func getBuilder(builderType string) IBuilder {
  if builderType == "normal" {
    return newNormalBuilder()
  }
  if builderType == "cottages" {
    return newCottagesBuilder()
  }
  return nil
}


  1. 新建具体建造者:普通房子 normalBuilder.go,在这个文件中,因为 Go 语言没有继承的概念,所以也需要我们定义跟 House 相同的结构体,然后实现 normalHouse 的构建 :
package main
type NormalBuilder struct {
  windowType string
  doorType   string
  swimPool   string
  floor      int
}
func newNormalBuilder() *NormalBuilder {
  return &NormalBuilder{}
}
func (b *NormalBuilder) setWindowType() {
  b.windowType = "Wooden Window"
}
func (b *NormalBuilder) setDoorType() {
  b.doorType = "Wooden Door"
}
func (b *NormalBuilder) setNumFloor() {
  b.floor = 3
}
func (b *NormalBuilder) setSwimPool() {
  b.swimPool = "None"
}
func (b *NormalBuilder) getHouse() House {
  return House{
    doorType:   b.doorType,
    windowType: b.windowType,
    swimPool:   b.swimPool,
    floor:      b.floor,
  }
}


  1. 跟上一步同理,新建别墅具体建设者 cottagesBuilder.go 文件,代码如下:
package main
type cottagesBuilder struct {
  windowType string
  doorType   string
  swimPool   string
  floor      int
}
func newCottagesBuilder() *cottagesBuilder {
  return &cottagesBuilder{}
}
func (b *cottagesBuilder) setWindowType() {
  b.windowType = "Glass Window"
}
func (b *cottagesBuilder) setDoorType() {
  b.doorType = "Steel Security Door"
}
func (b *cottagesBuilder) setNumFloor() {
  b.floor = 1
}
func (b *cottagesBuilder) setSwimPool() {
  b.swimPool = "Swimming Pool"
}
func (b *cottagesBuilder) getHouse() House {
  return House{
    doorType:   b.doorType,
    windowType: b.windowType,
    swimPool:   b.swimPool,
    floor:      b.floor,
  }
}
  1. 新建主管 director.go ,主管结构体内也是抽象建造者,其次主管有着 setBuilder()buildHouse() 的职责,最后主管负责安排负责对象的建造次序,比如先确定门、窗、楼层,再考虑是否需要加装泳池。最终代码如下:
package main
type Director struct {
  builder IBuilder
}
func newDirector(b IBuilder) *Director {
  return &Director{
    builder: b,
  }
}
func (d *Director) setBuilder(b IBuilder) {
  d.builder = b
}
func (d *Director) buildHouse() House {
  d.builder.setDoorType()
  d.builder.setWindowType()
  d.builder.setNumFloor()
  d.builder.setSwimPool()
  return d.builder.getHouse()
}


6.新建一个 main.go 文件,测试我们的创建者模式是否正确:

package main
import (
  "fmt"
)
func main() {
  normalBuilder := getBuilder("normal")
  cottagesBuilder := getBuilder("cottages")
  director := newDirector(normalBuilder)
  normalHouse := director.buildHouse()
  fmt.Printf("Normal House Door Type: %s\n", normalHouse.doorType)
  fmt.Printf("Normal House Window Type: %s\n", normalHouse.windowType)
  fmt.Printf("Normal House SwimPool: %s\n", normalHouse.swimPool)
  fmt.Printf("Normal House Num Floor: %d\n", normalHouse.floor)
  director.setBuilder(cottagesBuilder)
  cottagesHouse := director.buildHouse()
  fmt.Printf("\nCottage House Door Type: %s\n", cottagesHouse.doorType)
  fmt.Printf("Cottage House Window Type: %s\n", cottagesHouse.windowType)
  fmt.Printf("Cottage House SwimPool: %s\n", cottagesHouse.swimPool)
  fmt.Printf("Cottage House Num Floor: %d\n", cottagesHouse.floor)
}


  1. 最后,我们使用命令运行整个包 go run .


这是输出结果图:


image.png

优缺点

优点:


  • 你可以分步创建对象, 暂缓创建步骤或递归运行创建步骤。
  • 生成不同形式的产品时, 你可以复用相同的制造代码。
  • 单一职责原则。 你可以将复杂构造代码从产品的业务逻辑中分离出来。


缺点:


  • 由于该模式需要新增多个类, 因此代码整体复杂程度会有所增加。
相关文章
|
8天前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
12天前
|
程序员 Go 云计算
2023年学习Go语言是否值得?探索Go语言的魅力
2023年学习Go语言是否值得?探索Go语言的魅力
|
5天前
|
算法 NoSQL 中间件
go语言后端开发学习(六) ——基于雪花算法生成用户ID
本文介绍了分布式ID生成中的Snowflake(雪花)算法。为解决用户ID安全性与唯一性问题,Snowflake算法生成的ID具备全局唯一性、递增性、高可用性和高性能性等特点。64位ID由符号位(固定为0)、41位时间戳、10位标识位(含数据中心与机器ID)及12位序列号组成。面对ID重复风险,可通过预分配、动态或统一分配标识位解决。Go语言实现示例展示了如何使用第三方包`sonyflake`生成ID,确保不同节点产生的ID始终唯一。
go语言后端开发学习(六) ——基于雪花算法生成用户ID
|
6天前
|
JSON 缓存 监控
go语言后端开发学习(五)——如何在项目中使用Viper来配置环境
Viper 是一个强大的 Go 语言配置管理库,适用于各类应用,包括 Twelve-Factor Apps。相比仅支持 `.ini` 格式的 `go-ini`,Viper 支持更多配置格式如 JSON、TOML、YAML
go语言后端开发学习(五)——如何在项目中使用Viper来配置环境
|
17天前
|
Go
Go - 学习 grpc.Dial(target string, opts …DialOption) 的写法
Go - 学习 grpc.Dial(target string, opts …DialOption) 的写法
40 12
|
12天前
|
SQL 关系型数据库 MySQL
「Go开源」goose:深入学习数据库版本管理工具
「Go开源」goose:深入学习数据库版本管理工具
「Go开源」goose:深入学习数据库版本管理工具
|
13天前
|
设计模式 Go
go 设计模式之观察者模式
go 设计模式之观察者模式
|
1月前
|
Cloud Native Java Go
为什么要学习Go语言?
GO logo的核心理念,即简单胜于复杂。使用现代斜体无衬线字体与三条简单的运动线相结合,形成一个类似于快速运动的两个轮子的标记,传达速度和效率。字母的圆形暗示了GO地鼠的眼睛,创造了一个熟悉的形状,让标记和吉祥物很好地搭配在一起。
38 4
|
1月前
|
设计模式 Go
Go语言设计模式:使用Option模式简化类的初始化
在Go语言中,面对构造函数参数过多导致的复杂性问题,可以采用Option模式。Option模式通过函数选项提供灵活的配置,增强了构造函数的可读性和可扩展性。以`Foo`为例,通过定义如`WithName`、`WithAge`、`WithDB`等设置器函数,调用者可以选择性地传递所需参数,避免了记忆参数顺序和类型。这种模式提升了代码的维护性和灵活性,特别是在处理多配置场景时。
54 8
|
1月前
|
设计模式 JavaScript
js设计模式【详解】—— 建造者模式
js设计模式【详解】—— 建造者模式
22 0