建造者模式是一种创建型设计模式,它可以将一个复杂对象的构建和表示分离,让同样的构建过程可以创建不同的表示。建造者模式的目的是避免使用多个参数的构造函数或者多个可选参数的构造函数,而是通过一个步骤步骤的构建过程,来创建一个完整的对象。
在Go语言中,建造者模式可以通过接口和结构体来实现。接口定义了建造者的抽象,它有一些方法,用于设置不同的属性或组件。结构体实现了具体的建造者,它包含了一个产品类型的字段,用于存储构建过程中的结果。结构体也有一个方法,用于返回最终的产品对象。
一个例子
假设我们要开发一个汽车制造的应用,它可以支持不同的汽车类型和不同的配置选项。我们可以使用建造者模式来设计这个应用,如下图所示:
在这个图中,我们定义了一个接口:CarBuilder
。CarBuilder
表示汽车建造者的抽象,它有四个方法:SetSeats()
,SetEngine()
,SetTripComputer()
和SetGPS()
,用于设置汽车的不同属性或组件。
我们还定义了两个结构体:Car
和CarManual
。Car
表示汽车产品的结构体,它包含了四个字段:seats
,engine
,tripComputer
和gps
,分别表示汽车的座位数,引擎类型,行车电脑和GPS导航系统。CarManual
表示汽车手册产品的结构体,它也包含了四个字段:seats
,engine
,tripComputer
和
gps
,分别表示汽车手册中的座位数,引擎类型,行车电脑和GPS导航系统的说明。
我们还定义了两个结构体:CarBuilderImpl
和CarManualBuilderImpl
,分别实现了CarBuilder
接口,并提供了不同的建造逻辑。CarBuilderImpl
包含了一个Car
类型的字段,用于存储构建过程中的结果。它的每个方法都会设置相应的属性或组件,并返回自身,以便于链式调用。它还有一个方法GetResult()
,用于返回最终的汽车对象。CarManualBuilderImpl
包含了一个CarManual
类型的字段,用于存储构建过程中的结果。它的每个方法都会设置相应的属性或组件,并返回自身,以便于链式调用。它还有一个方法GetResult()
,用于返回最终的汽车手册对象。
代码实现
下面是一个简单的代码实现,展示了如何使用建造者模式来创建和使用汽车和汽车手册:
代码语言:javascript复制package main
import "fmt"
// CarBuilder is the abstract interface for car builders
type CarBuilder interface {
SetSeats(int) CarBuilder
SetEngine(string) CarBuilder
SetTripComputer(bool) CarBuilder
SetGPS(bool) CarBuilder
GetResult() interface{}
}
// Car is the product struct for cars
type Car struct {
seats int
engine string
tripComputer bool
gps bool
}
// CarManual is the product struct for car manuals
type CarManual struct {
seats string
engine string
tripComputer string
gps string
}
// CarBuilderImpl is the concrete struct for car builder
type CarBuilderImpl struct {
car *Car // the reference to the car product
}
// SetSeats is the method of CarBuilderImpl to set seats
func (c *CarBuilderImpl) SetSeats(seats int) CarBuilder {
c.car.seats = seats // set the seats field of the car product
return c // return itself for chaining
}
// SetEngine is the method of CarBuilderImpl to set engine
func (c *CarBuilderImpl) SetEngine(engine string) CarBuilder {
c.car.engine = engine // set the engine field of the car product
return c // return itself for chaining
}
// SetTripComputer is the method of CarBuilderImpl to set trip computer
func (c *CarBuilderImpl) SetTripComputer(tripComputer bool) CarBuilder {
c.car.tripComputer = tripComputer // set the trip computer field of the car product
return c // return itself for chaining
}
// SetGPS is the method of CarBuilderImpl to set GPS
func (c *CarBuilderImpl) SetGPS(gps bool) CarBuilder {
c.car.gps = gps // set the GPS field of the car product
return c // return itself for chaining
}
// GetResult is the method of CarBuilderImpl to get the car product
func (c *CarBuilderImpl) GetResult() interface{} {
return c.car // return the car product
}
// CarManualBuilderImpl is the concrete struct for car manual builder
type CarManualBuilderImpl struct {
manual *CarManual // the reference to the car manual product
}
// SetSeats is the method of CarManualBuilderImpl to set seats
func (c *CarManualBuilderImpl) SetSeats(seats int) CarBuilder {
c.manual.seats = fmt.Sprintf("The car has %d seats", seats) // set the seats field of the car manual product with some explanation
return c // return itself for chaining
}
// SetEngine is the method of CarManualBuilderImpl to set engine
func (c *CarManualBuilderImpl) SetEngine(engine string) CarBuilder {
c.manual.engine = fmt.Sprintf("The car has a %s engine", engine) // set the engine field of the car manual product with some explanation
return c // return itself for chaining
}
// SetTripComputer is the method of CarManualBuilderImpl to set trip computer
func (c *CarManualBuilderImpl) SetTripComputer(tripComputer bool) CarBuilder {
if tripComputer {
c.manual.tripComputer = "The car has a trip computer" // set the trip computer field of the car manual product with some explanation
} else {
c.manual.tripComputer = "The car does not have a trip computer" // set the trip computer field of the car manual product with some explanation
}
return c // return itself for chaining
}
// SetGPS is the method of CarManualBuilderImpl to set GPS
func (c *CarManualBuilderImpl) SetGPS(gps bool) CarBuilder {
if gps {
c.manual.gps = "The car has a GPS system" // set the GPS field of the car manual product with some explanation
} else {
c.manual.gps = "The car does not have a GPS system" // set the GPS field of the car manual product with some explanation
}
return c // return itself for chaining
}
// GetResult is the method of CarManualBuilderImpl to get the car manual product
func (c *CarManualBuilderImpl) GetResult() interface{} {
return c.manual // return the car manual product
}
func main() {
// create a car builder and a car manual builder
carBuilder := &CarBuilderImpl{car: &Car{}}
carManualBuilder := &CarManualBuilderImpl{manual: &CarManual{}}
// build a sports car and its manual
sportsCar := carBuilder.SetSeats(2).SetEngine("V8").SetTripComputer(true).SetGPS(true).GetResult().(*Car)
sportsCarManual := carManualBuilder.SetSeats(2).SetEngine("V8").SetTripComputer(true).SetGPS(true).GetResult().(*CarManual)
// print the sports car and its manual
fmt.Println("Sports Car:")
fmt.Printf("Seats: %dn", sportsCar.seats)
fmt.Printf("Engine: %sn", sportsCar.engine)
fmt.Printf("Trip Computer: %tn", sportsCar.tripComputer)
fmt.Printf("GPS: %tn", sportsCar.gps)
fmt.Println("Sports Car Manual:")
fmt.Printf("Seats: %sn", sportsCarManual.seats)
fmt.Printf("Engine: %sn", sportsCarManual.engine)
fmt.Printf("Trip Computer: %sn", sportsCarManual.tripComputer)
fmt.Printf("GPS: %sn", sportsCarManual.gps)
// output:
// Sports Car:
// Seats: 2
// Engine: V8
// Trip Computer: true
// GPS: true
// Sports Car Manual:
// Seats: The car has 2 seats
// Engine: The car has a V8 engine
// Trip Computer: The car has a trip computer
// GPS: The car has a GPS system
// build a city car and its manual
cityCar := carBuilder.SetSeats(4).SetEngine("V4").SetTripComputer(false).SetGPS(false).GetResult().(*Car)
cityCarManual := carManualBuilder.SetSeats(4).SetEngine("V4").SetTripComputer(false).SetGPS(false).GetResult().(*CarManual)
// print the city car and its manual
fmt.Println("City Car:")
fmt.Printf("Seats: %dn", cityCar.seats)
fmt.Printf("Engine: %sn", cityCar.engine)
fmt.Printf("Trip Computer: %tn", cityCar.tripComputer)
fmt.Printf("GPS: %tn", cityCar.gps)
fmt.Println("City Car Manual:")
fmt.Printf("Seats: %sn", cityCarManual.seats)
fmt.Printf("Engine: %sn", cityCarManual.engine)
fmt.Printf("Trip Computer: %sn", cityCarManual.tripComputer)
fmt.Printf("GPS: %sn", cityCarManual.gps)
// output:
// City Car:
// Seats: 4
// Engine: V4
// Trip Computer: false
// GPS: false
// City Car Manual:
// Seats: The car has 4 seats
// Engine: The car has a V4 engine
// Trip Computer: The car does not have a trip computer
// GPS: The car does not have a GPS system
}
总结
建造者模式可以让我们将一个复杂对象的构建和表示分离,从而实现更好的可控制性和灵活性。在Go语言中,我们可以使用接口和结构体来实现建造者模式,通过一个步骤步骤的构建过程,来创建一个完整的对象。