设计模式之建造者模式
建造者模式又称为生成器模式,建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品
概述
建造者模式是较为复杂的创建型模式,它将客户端与包含多个组成部分的复杂对象的创建过程分离,客户端无须知道复杂对象的内部组成部分与装配方式,只需要知道所创建的建造者类型即可。建造者关注如何一步步创建一个复杂对象,不同的建造者定义了不同的创建过程,而且具体的建造者相互独立,增加新的建造者也无须修改已有的代码,具有比较好的拓展性,建造者允许用户只通过制定复杂对象的类型和内容就可以构建他们,用户不需要知道内部的具体细节
定义
建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式
建造者模式包含4个角色
- Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法:一类是builderPartX(),用于创建复杂对象的各个部件,另一类方法是getResult(),用于返回复杂对象。
- ConcreteBuilder(具体建造者):他实现了Builder接口,实现了各个部件的具体构造和装配方法,定义并明确了其所创建的复杂对象,也提供一个方法返回创建好的复杂产品对象
- Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义其装配过程
- Director(指挥者): 它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造,客户端一般只需要和指挥者交互
什么是复杂对象?复杂对象就是包含多个成员变量的对象
组装电脑
我们以组装电脑为例子,假设我们需要组装不同CPU,内存,硬盘,以及显卡的电脑,我们可以把这个过程模拟成建造者模式,以下是代码实现
package builder
type Builder interface {
InstallCpu()
InstallMemory()
InstallHardDisk()
InstallMobo()
InstallGpu()
GetComputer() Computer
}
type Computer struct {
Cpu string // cpu
Memory string // 内存
HardDisk string // 硬盘
Mobo string // 主板
Gpu string // 显卡
}
type Director struct {
ComputerBuilder Builder
}
func NewDirector(computerBuilder Builder) *Director {
return &Director{
ComputerBuilder: computerBuilder,
}
}
func (d *Director) Construct() Computer {
d.ComputerBuilder.InstallCpu()
d.ComputerBuilder.InstallMobo()
d.ComputerBuilder.InstallHardDisk()
d.ComputerBuilder.InstallMemory()
d.ComputerBuilder.InstallGpu()
return d.ComputerBuilder.GetComputer()
}
// OfficeComputer 办公电脑
type OfficeComputer struct {
Computer Computer
}
// GameComputer 游戏电脑
type GameComputer struct {
Computer Computer
}
func NewOfficeComputer() *OfficeComputer {
return &OfficeComputer{
Computer: Computer{},
}
}
func NewGameComputer() *GameComputer {
return &GameComputer{
Computer: Computer{},
}
}
func (o *OfficeComputer) InstallCpu() {
o.Computer.Cpu = "Intel H610"
}
func (o *OfficeComputer) InstallMemory() {
o.Computer.Memory = "8G"
}
func (o *OfficeComputer) InstallHardDisk() {
o.Computer.HardDisk = "256G"
}
func (o *OfficeComputer) InstallMobo() {
o.Computer.Mobo = "华硕(ASUS)PRIME H610M-A D4主板"
}
func (o *OfficeComputer) InstallGpu() {
o.Computer.Gpu = "核显"
}
func (o *OfficeComputer) GetComputer() Computer {
return o.Computer
}
func (g *GameComputer) InstallCpu() {
g.Computer.Cpu = "i5-12400"
}
func (g *GameComputer) InstallMemory() {
g.Computer.Memory = "16G"
}
func (g *GameComputer) InstallHardDisk() {
g.Computer.HardDisk = "500G"
}
func (g *GameComputer) InstallMobo() {
g.Computer.Mobo = "华硕B660M电竞主板"
}
func (g *GameComputer) InstallGpu() {
g.Computer.Gpu = "RTX3050"
}
func (g *GameComputer) GetComputer() Computer {
return g.Computer
}
这里的Builder,就是一个接口,定义了一些组装的方法,同时也定义了一个GetComputer来获取最终得到的电脑
type Builder interface {
InstallCpu()
InstallMemory()
InstallHardDisk()
InstallMobo()
InstallGpu()
GetComputer() Computer
}
同时定一个结构体Computer,里面包含了许多的属性
type Computer struct {
Cpu string // cpu
Memory string // 内存
HardDisk string // 硬盘
Mobo string // 主板
Gpu string // 显卡
}
还定义了OfficeComputer以及GameComputer来作为建造者,实现Builder的方法
// OfficeComputer 办公电脑
type OfficeComputer struct {
Computer Computer
}
// GameComputer 游戏电脑
type GameComputer struct {
Computer Computer
}
func NewOfficeComputer() *OfficeComputer {
return &OfficeComputer{
Computer: Computer{},
}
}
func NewGameComputer() *GameComputer {
return &GameComputer{
Computer: Computer{},
}
}
func (o *OfficeComputer) InstallCpu() {
o.Computer.Cpu = "Intel H610"
}
func (o *OfficeComputer) InstallMemory() {
o.Computer.Memory = "8G"
}
func (o *OfficeComputer) InstallHardDisk() {
o.Computer.HardDisk = "256G"
}
func (o *OfficeComputer) InstallMobo() {
o.Computer.Mobo = "华硕(ASUS)PRIME H610M-A D4主板"
}
func (o *OfficeComputer) InstallGpu() {
o.Computer.Gpu = "核显"
}
func (o *OfficeComputer) GetComputer() Computer {
return o.Computer
}
func (g *GameComputer) InstallCpu() {
g.Computer.Cpu = "i5-12400"
}
func (g *GameComputer) InstallMemory() {
g.Computer.Memory = "16G"
}
func (g *GameComputer) InstallHardDisk() {
g.Computer.HardDisk = "500G"
}
func (g *GameComputer) InstallMobo() {
g.Computer.Mobo = "华硕B660M电竞主板"
}
func (g *GameComputer) InstallGpu() {
g.Computer.Gpu = "RTX3050"
}
func (g *GameComputer) GetComputer() Computer {
return g.Computer
}
最后,我们定义了一个指挥者,用来做最后的对象创建
type Director struct {
ComputerBuilder Builder
}
func NewDirector(computerBuilder Builder) *Director {
return &Director{
ComputerBuilder: computerBuilder,
}
}
func (d *Director) Construct() Computer {
d.ComputerBuilder.InstallCpu()
d.ComputerBuilder.InstallMobo()
d.ComputerBuilder.InstallHardDisk()
d.ComputerBuilder.InstallMemory()
d.ComputerBuilder.InstallGpu()
return d.ComputerBuilder.GetComputer()
测试
package builder
import (
"fmt"
"testing"
)
func TestDirector_Construct(t *testing.T) {
officeComputerBuilder := NewOfficeComputer()
officeDirector := NewDirector(officeComputerBuilder)
computer := officeDirector.Construct()
fmt.Println(computer)
gameComputerBuilder := NewGameComputer()
gameDirector := NewDirector(gameComputerBuilder)
gameComputer := gameDirector.Construct()
fmt.Println(gameComputer)
}
//
// === RUN TestDirector_Construct
// {Intel H610 8G 256G 华硕(ASUS)PRIME H610M-A D4主板 核显}
// {i5-12400 16G 500G 华硕B660M电竞主板 RTX3050}
// --- PASS: TestDirector_Construct (0.00s)
// PASS
总结
优点
- 在建造者模式中,客户端不必知道产品内部的创建细节,将产品本身和产品的创建过程解耦,使得创建过程相同可以创建不同的产品对象
- 每一个具体的建造者都相对独立,而与其他的具体建造者无关,增加新的建造者无需修改原有的建造者的代码
- 可以更加精细的控制产品的创建过程,将复杂的产品的创建步骤分解在不同的方法中,是的创建过程更加清晰
缺点
- 建造者创建的产品一般具有较多的共同电,如果产品之间的差异性很大,则不适合
- 如果产品内部结构复杂且多变,可能需要定义很多的建造者,会使得系统变得庞大