Golang学习笔记_30——建造者模式

发布于:2025-02-13 ⋅ 阅读:(97) ⋅ 点赞:(0)

Golang学习笔记_27——单例模式
Golang学习笔记_28——工厂方法模式
Golang学习笔记_29——抽象工厂模式



一、建造者模式核心概念

1. 定义

建造者模式是一种 创建型设计模式,用于 分步骤构造复杂对象。它将对象的构造过程与其表示分离,使得同样的构造过程可以创建不同的表示。

2. 解决的问题

  • 复杂对象的构造逻辑混乱:当一个对象需要多个步骤或参数才能构造完成时,直接通过构造函数或工厂方法会导致参数爆炸(如构造函数参数过多)。
  • 构造过程需要灵活控制:例如,某些场景需要跳过某些构造步骤,或改变步骤顺序。

3. 核心角色

  1. Director(指挥者):负责调用建造者的步骤方法,控制构造流程。
  2. Builder(抽象建造者):定义构造对象的步骤接口(如 BuildPartA(), BuildPartB())。
  3. ConcreteBuilder(具体建造者):实现 Builder 接口,提供具体构造逻辑,并返回最终结果。
  4. Product(产品):最终要构造的复杂对象。

4. 类图(与下方示例一致)

在这里插入图片描述

二、建造者模式的特点

优点

  1. 分步构造复杂对象
    将复杂对象的构造过程拆解为多个步骤,代码更清晰。

  2. 复用构造过程
    通过不同的 ConcreteBuilder,可以用相同的构造逻辑生成不同的对象表示。

  3. 隐藏产品细节
    客户端不需要知道产品的内部组成和构造细节。

  4. 灵活控制构造流程
    Director 可以灵活调整构造步骤(例如跳过某些步骤)。

缺点

  1. 代码复杂度增加
    需要定义多个类(Builder、Director、Product),对简单对象可能过度设计。

  2. 产品需高度一致
    如果产品之间的差异极大,建造者模式可能不适用(需频繁修改 Builder 接口)。

三、适用场景

1. 构造复杂对象

  • 对象需要多个步骤或组件组合而成。
  • 示例:构造一个包含 CPU、内存、硬盘的电脑配置。

2. 构造过程需要灵活控制

  • 构造步骤的顺序或内容需要动态调整。
  • 示例:生成不同格式的报告(HTML/PDF),步骤相同但实现不同。

3. 避免构造函数参数爆炸

  • 当构造函数参数过多时(如超过 4 个),使用建造者模式更清晰。
  • 示例:创建用户对象(姓名、年龄、地址、电话、邮箱等)。

4. 需要生成不同表示的对象

  • 同一构造过程需要生成不同表现形式的结果。
  • 示例:同一数据源生成表格、图表、文本三种展示形式。

四、与其他创建型模式的对比

模式 核心目标 关键区别
工厂方法 创建单一对象 直接返回完整对象,不涉及分步构造。
抽象工厂 创建产品族(多个相关对象) 关注产品家族的兼容性,而非分步构造。
建造者 分步骤构造复杂对象 强调构造过程的控制和步骤拆分。
原型 通过克隆生成对象 避免重复初始化,直接复制现有对象。

五、Go 语言代码示例

场景描述

构造一台电脑(Computer),包含 CPU、内存、硬盘等组件,支持不同配置(游戏电脑、办公电脑)。

代码实现

package builder_demo

import "fmt"

// product
type Computer struct {
   CPU      string
   Memory   string
   HardDisk string
}

func (c Computer) show() {
   fmt.Printf("电脑配置:\n  CPU: %s\n  内存: %s\n  硬盘: %s\n\n", c.CPU, c.Memory, c.HardDisk)
}

// Builder Interface
type ComputerBuilder interface {
   buildCPU() ComputerBuilder
   buildMemory() ComputerBuilder
   buildHardDisk() ComputerBuilder
   build() Computer
}

// ConcreteBuilder
type GamingComputerBuilder struct {
   computer Computer
}

func (g *GamingComputerBuilder) buildCPU() ComputerBuilder {
   g.computer.CPU = "Intel i9"
   return g
}

func (g *GamingComputerBuilder) buildMemory() ComputerBuilder {
   g.computer.Memory = "32G"
   return g
}

func (g *GamingComputerBuilder) buildHardDisk() ComputerBuilder {
   g.computer.HardDisk = "512G SSD"
   return g
}

func (g *GamingComputerBuilder) build() Computer {
   return g.computer
}

// ConcreteBuilder
type OfficeComputerBuilder struct {
   computer Computer
}

func (o *OfficeComputerBuilder) buildCPU() ComputerBuilder {
   o.computer.CPU = "Intel i7"
   return o
}

func (o *OfficeComputerBuilder) buildMemory() ComputerBuilder {
   o.computer.Memory = "16G"
   return o
}

func (o *OfficeComputerBuilder) buildHardDisk() ComputerBuilder {
   o.computer.HardDisk = "1T HDD"
   return o
}
func (o *OfficeComputerBuilder) build() Computer {
   return o.computer
}

// Director
type Director struct {
   builder ComputerBuilder
}

func (d *Director) Construct() Computer {
   return d.builder.buildCPU().buildMemory().buildHardDisk().build()
}

func test() {
   // 组装游戏电脑
   director := Director{}
   gamingComputerBuilder := &GamingComputerBuilder{}
   director.builder = gamingComputerBuilder
   director.Construct().show()

   // 组装办公电脑
   director.builder = &OfficeComputerBuilder{}
   director.Construct().show()

}

输出结果

=== RUN   Test_test
电脑配置:
  CPU: Intel i9
  内存: 32G
  硬盘: 512G SSD

电脑配置:
  CPU: Intel i7
  内存: 16G
  硬盘: 1T HDD

--- PASS: Test_test (0.00s)
PASS

六、建造者模式的高级用法

1. 链式调用

通过返回 Builder 自身实现链式调用(如上述代码中的 SetCPU().SetMemory())。

2. 可选构造步骤

Director 中动态决定是否执行某些步骤:

func (d *Director) Construct(needDisk bool) Computer {
	builder := d.builder.SetCPU().SetMemory()
	if needDisk {
		builder = builder.SetDisk()
	}
	return builder.Build()
}

3. 参数校验

Build() 方法中校验参数合法性:

func (b *GamingComputerBuilder) Build() Computer {
	if b.computer.CPU == "" {
		panic("CPU 未配置!")
	}
	return b.computer
}

4. 演示

package builder_demo

import "fmt"

// Order 订单对象
type Order struct {
	UserID  string
	Items   []string
	Address string
	Coupon  string
	Notes   string
}

// Print 打印订单信息
func (o *Order) Print() {
	fmt.Printf("订单详情:\n"+
		"  用户ID: %s\n"+
		"  商品: %v\n"+
		"  地址: %s\n"+
		"  优惠券: %s\n"+
		"  备注: %s\n",
		o.UserID, o.Items, o.Address, o.Coupon, o.Notes)
}

// OrderBuilder Builder 订单建造者
type OrderBuilder struct {
	order Order
}

// SetUserID 链式方法: 设置用户ID
func (b *OrderBuilder) SetUserID(userID string) *OrderBuilder {
	b.order.UserID = userID
	return b
}

// AddItem 链式方法: 添加商品
func (b *OrderBuilder) AddItem(item string) *OrderBuilder {
	b.order.Items = append(b.order.Items, item)
	return b
}

// SetAddress 链式方法: 设置地址
func (b *OrderBuilder) SetAddress(address string) *OrderBuilder {
	b.order.Address = address
	return b
}

// SetCoupon 链式方法: 设置优惠券
func (b *OrderBuilder) SetCoupon(coupon string) *OrderBuilder {
	b.order.Coupon = coupon
	return b
}

// SetNotes 链式方法: 设置备注
func (b *OrderBuilder) SetNotes(notes string) *OrderBuilder {
	b.order.Notes = notes
	return b
}

// Build 链式方法: 构建订单
func (b *OrderBuilder) Build() Order {
	// 信息校验
	if b.order.UserID == "" {
		panic("用户ID不能为空")
	}
	if len(b.order.Items) == 0 {
		panic("商品不能为空")
	}
	return b.order
}

func test2() {
	builder := OrderBuilder{}
	order := builder.
		SetUserID("123456").
		AddItem("商品1").
		AddItem("商品2").
		SetAddress("北京市朝阳区").
		SetCoupon("满100减20").
		SetNotes("备注信息").
		Build()
	order.Print()
}

输出结果

=== RUN   Test_test2
订单详情:
  用户ID: 123456
  商品: [商品1 商品2]
  地址: 北京市朝阳区
  优惠券: 满100减20
  备注: 备注信息
--- PASS: Test_test2 (0.00s)
PASS

七、总结

建造者模式通过 分步骤构造对象隔离构造逻辑,解决了复杂对象创建的灵活性问题。适用于以下场景:

  1. 对象构造过程复杂,涉及多个步骤。
  2. 需要生成不同表示的对象。
  3. 避免构造函数参数过多。

结合链式调用、参数校验等技巧,可以进一步提升代码的可读性和健壮性。如果需要更具体的扩展场景(如结合工厂模式),可以告诉我! 🚀