介绍
建造者模式(Builder Pattern)是一种创建型设计模式,它将对象的构建过程与其表示分离,使得相同的构建过程可以创建不同的表示。客户端无需知道复杂对象的内部实现方式,只需要知道所需的建造者类型即可。
建造者模式的核心思想是将对象的构建过程委派给一个独立的构建者类,该类负责控制对象的创建细节。它将对象的构建过程分解为一系列步骤,并通过一系列方法来设置对象的属性和状态,最终产生一个完整的对象。
说人话就是:你去买车,你不会只买一个轮胎、一个发动机、一个方向盘,你买的是一辆包括轮胎、方向盘、发动机、底盘、电气系统和车身等多个部件组成的完整汽车。
建造者模式就是解决如何将这些部件组装成一辆完整的汽车并返回给用户的设计模式。建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品。
角色
- 产品(Product):表示最终构建的复杂对象。它通常具有多个组成部分,并且可以由不同的构建者创建不同的表示。
- 构建者(Builder):定义了构建产品对象的抽象接口。它包含了构建产品各个部分的方法,以及返回最终构建结果的方法。
- 具体构建者(Concrete Builder):实现了构建者接口,负责具体产品的构建过程。它实现了构建产品各个部分的方法,并返回最终构建的产品。
- 导演(Director):负责使用构建者对象来构建复杂对象。它并不直接与产品交互,而是通过构建者来构建产品,实现了构建过程的控制。
优点
- 可以分步创建对象,更好的控制创建步骤。
- 生产不同的产品时,可以复用相同的代码。
- 将复杂的构造代码从产品逻辑中分离出来。
- 通过增加新的具体建造者类,可以方便地扩展和改变产品的构建过程,而不需要修改导演类或客户端代码,易于扩展。
缺点
- 建造者模式会增加额外的建造者类和产品类,增加了代码量和类的数量,可能会增加系统的复杂性。
使用场景
- 当需要构建复杂对象,并且对象的构建过程需要在不同的步骤中进行灵活的配置时,可以考虑使用建造者模式。
- 当需要构建的产品具有多个部分或属性,并且这些部分可以按照不同的顺序或配置组装时,可以使用建造者模式。
- 当需要构建的产品对象的组成部分存在复杂的变化,在构建过程中需要动态地组装不同的部件时,建造者模式可以提供一种灵活的解决方案。
代码示例
package main
import "fmt"
// 定义产品类 Computer
type Computer struct {
CPU string
Memory string
Storage string
}
// 定义抽象建造者接口 ComputerBuilder
type ComputerBuilder interface {
BUildCPU()
BUildMemory()
BUildStorage()
GetComputer() Computer
//GetComputer() *Computer
}
// 定义具体建造者类,高配电脑
type HighComputerBuilder struct {
//computer *Computer
computer Computer
}
func (h *HighComputerBuilder) BUildCPU() {
h.computer.CPU = "Intel Core i9"
//h.computer = &Computer{CPU: "Intel Core i7"}
}
func (h *HighComputerBuilder) BUildMemory() {
h.computer.Memory = "1TB"
}
func (h *HighComputerBuilder) BUildStorage() {
h.computer.Storage = "2TB"
}
// func (h *HighComputerBuilder) GetComputer() *Computer
func (h *HighComputerBuilder) GetComputer() Computer {
return h.computer
}
// 定义具体建造者类,低配电脑
type LowComputerBuilder struct {
//computer *Computer
computer Computer
}
func (l *LowComputerBuilder) BUildCPU() {
l.computer.CPU = "Intel Core i5"
//l.computer = &Computer{CPU: "Intel Core i5"}
}
func (l *LowComputerBuilder) BUildMemory() {
l.computer.Memory = "16GB"
}
func (l *LowComputerBuilder) BUildStorage() {
l.computer.Storage = "500GB"
}
// func (l *LowComputerBuilder) GetComputer() *Computer
func (l *LowComputerBuilder) GetComputer() Computer {
return l.computer
}
// 定义导演类 Director
type Director struct {
builder ComputerBuilder
}
func (d *Director) Construct() {
d.builder.BUildCPU()
d.builder.BUildMemory()
d.builder.BUildStorage()
}
func (d *Director) GetComputer() Computer {
return d.builder.GetComputer()
}
func main() {
high := &HighComputerBuilder{}
director := &Director{builder: high}
director.Construct()
computer := director.GetComputer()
fmt.Println("高配电脑配置是:")
fmt.Println("CPU:", computer.CPU)
fmt.Println("内存:", computer.Memory)
fmt.Println("存储:", computer.Storage)
low := &LowComputerBuilder{}
director = &Director{builder: low}
director.Construct()
computer = director.GetComputer()
fmt.Println("低配电脑配置是:")
fmt.Println("CPU:", computer.CPU)
fmt.Println("内存:", computer.Memory)
fmt.Println("存储:", computer.Storage)
}
如果computer类型为指针,那么在使用该建造者类时需要确保在构建过程中已经正确初始化了computer
字段,否则在调用GetComputer()
方法时可能会导致空指针错误。所以在BuildCPU()
方法中使用&Computer{CPU: "Intel Core i7"}
来初始化computer
字段,