建造者模式
简介
建造者模式(Builder Pattern),也可以称为“生成器模式”,其目标是将复杂对象的构造与其实现分离,以便相同的构造过程可以创建不同的实现。建造者模式主要用于逐步构建一个复杂的对象,并且返回该对象。
UML
nil
角色组成
- 建造者(Builder):定义了正确创建产品必须采取的所有步骤的接口。每个步骤通常是抽象的,因为建造者的实际功能实在具体的实现类中实现的。
- 具体建造者(ConcrecateBuilder):实现建造者接口的累哦。具体建造者可以生产任意数量的产品类,这些类具有创建特定复杂产品的功能。
- 产品(Product):最终生成的对象。由不同具体建造者创建的产品是独立的,产品之间不受影响。
- 主管(Director):用于控制生成最终产品对象算法的类。主管对象会被实例化,并且它生成产品对象的方法
Construct()
被调用,该方法中包含一个参数,用于捕获生成产品的特定具体建造者。 - 客户端(Client):将某个建造者对象与主管类相关联。
适用场景
- 当开发者希望创建不同形式的产品时
- 不同形式的产品的制造过程相似且产品之间的差别不大
- 构造函数的参数很多
- 当需要构建同一个对象的不同表示时
优点
- 产品组成细节对客户端不可见,将产品的构建过程和产品解耦
- 每个具体建造者都相对独立,可以方便替换和扩展建造者,无需修改原有类库的代码,符合开闭原则
- 复杂产品的创建步骤分解在不同方法中,使创建过程更清晰,更易于程 序控制创建过程
缺点
- 使用建造者模式创建的产品组成部分都类似,如果产品之间的差异很大,则不适用建造者模式
- 需要为不同类型的产品单独创建具体建造者,代码量较大
示例代码
Go
builder.go
package BuilderPattern
// 定义建造者接口
type Builder interface {
SetSeatsType()
SetEngineType()
SetNumber()
GetCar() Car
}
// 产品类
type Car struct {
SeatsType string
EngineType string
Number int
}
// 获取建造者对象
func GetBuilder(BuilderType string) Builder {
if BuilderType == "mpv" {
return &MpvBuilder{}
}
if BuilderType == "suv" {
return &SuvBuilder{}
}
return nil
}
// 具体建造者类 MPV
type MpvBuilder struct {
SeatsType string
EngineType string
Number int
}
func NewMpvBuilder() *MpvBuilder {
return &MpvBuilder{}
}
func (b *MpvBuilder) SetSeatsType() {
b.SeatsType = "MPV型座椅"
}
func (b *MpvBuilder) SetEngineType() {
b.EngineType = "MPV型发动机"
}
func (b *MpvBuilder) SetNumber() {
b.Number = 8
}
func (b *MpvBuilder) GetCar() Car {
return Car{
EngineType: b.EngineType,
SeatsType: b.SeatsType,
Number: b.Number,
}
}
// 具体建造者类 Suv
type SuvBuilder struct {
SeatsType string
EngineType string
Number int
}
func NewSuvBuilder() *SuvBuilder {
return &SuvBuilder{}
}
func (b *SuvBuilder) SetSeatsType() {
b.SeatsType = "SUV型座椅"
}
func (b *SuvBuilder) SetEngineType() {
b.EngineType = "SUV型发动机"
}
func (b *SuvBuilder) SetNumber() {
b.Number = 6
}
func (b *SuvBuilder) GetCar() Car {
return Car{
EngineType: b.EngineType,
SeatsType: b.SeatsType,
Number: b.Number,
}
}
// 主管类
type Director struct {
Builder Builder
}
func NewDirector(b Builder) *Director {
return &Director{Builder: b}
}
func (d *Director) SetBuilder(b Builder) {
d.Builder = b
}
func (d *Director) BuildCar() Car {
d.Builder.SetSeatsType()
d.Builder.SetEngineType()
d.Builder.SetNumber()
return d.Builder.GetCar()
}
客户端测试 builder_test.go
package BuilderPattern
import "testing"
func TestBuilder(t *testing.T) {
mpvBuilder := NewMpvBuilder()
suvBuilder := NewSuvBuilder()
director := NewDirector(mpvBuilder)
mpvcar := director.BuildCar()
t.Logf("mpvcar: %+v", mpvcar)
director.SetBuilder(suvBuilder)
suvcar := director.BuildCar()
t.Logf("suvcar: %+v", suvcar)
}
Python
from abc import ABCMeta, abstractmethod
class Builder(metaclass=ABCMeta):
"""建造者基类"""
@abstractmethod
def set_seats_type(self):
pass
@abstractmethod
def set_engine_type(self):
pass
@abstractmethod
def set_number(self):
pass
@abstractmethod
def get_car(self):
pass
class Car:
"""产品类"""
def __init__(self, seats_type: str, engine_type: str, number: int):
self.seats_type = seats_type
self.engine_type = engine_type
self.number = number
class MPVBuilder(Builder):
seats_type = ""
engine_type = ""
number = 0
def set_seats_type(self):
self.seats_type = "MPV 型座椅"
def set_engine_type(self):
self.engine_type = "MPV 型引擎"
def set_number(self):
self.number = 8
def get_car(self) -> Car:
return Car(self.seats_type, self.engine_type, self.number)
class SUVBuilder(Builder):
seats_type = ""
engine_type = ""
number = 0
def set_seats_type(self):
self.seats_type = "SUV 型座椅"
def set_engine_type(self):
self.engine_type = "SUV 型引擎"
def set_number(self):
self.number = 6
def get_car(self) -> Car:
return Car(self.seats_type, self.engine_type, self.number)
class Director:
def __init__(self, builder: Builder):
self.builder = builder
def set_builder(self, b: Builder):
self.builder = b
def build_car(self) -> Car:
self.builder.set_seats_type()
self.builder.set_engine_type()
self.builder.set_number()
return self.builder.get_car()
def new_builder(b: Builder) -> Director:
return Director(b)
def get_builder(builder_type: str) -> Builder:
if builder_type.lower() == "mpv":
return MPVBuilder()
elif builder_type.lower() == "suv":
return SUVBuilder()
else:
raise ValueError("Invalid builder type")
if __name__ == "__main__":
mpv_builder = MPVBuilder()
suv_builder = SUVBuilder()
director = new_builder(mpv_builder)
mpv_car = director.build_car()
print(
f"mpv engine: {mpv_car.engine_type}, seats: {mpv_car.seats_type}, number: {mpv_car.number}"
)
director.set_builder(suv_builder)
suv_car = director.build_car()
print(
f"suv engine: {suv_car.engine_type}, seats: {suv_car.seats_type}, number: {suv_car.number}"
)