This repository has been archived on 2021-09-07. You can view files and clone it, but cannot push or open issues or pull requests.
2018-11-26 16:40:59 +08:00

137 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 建造者模式
最近一直在写框架,这个系列也好久没更新了,抽时间更新一篇~
### 概述
> wiki: **建造者模式(Builder Pattern)**:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
直白一点的说,就是将我们在开发过程中遇到的大型对象,拆分成多个小对象,然后将多个小对象组装成大对象,并且对外部隐藏建造过程.
### 结构
建造者模式由一下4个部分组成
- `Builder`: 抽象建造者
- `ConcreteBuilder`: 具体建造者
- `Director`: 指挥者
- `Production`: 产品(大型产品以及拆分成的小型产品)
### 类图 && 时序图
![](https://design-patterns.readthedocs.io/zh_CN/latest/_images/Builder.jpg)
![](https://design-patterns.readthedocs.io/zh_CN/latest/_images/seq_Builder.jpg)
-----------
(*图源网络*)
从上面两张图可以看出建造者模式的使用流程:
1. 创建大型产品建造者
2. 创建指挥者
3. 将建造者传入指挥者对象中
4. 由指挥者指挥建造者创建对象,并返回
### 举个栗子
说一个网上说烂了的组装汽车的栗子吧,
比如说我是个老司机,但是除了开车还想造车,但是车的构造实在是太复杂了,那么我们就可以将车拆分...
4个轮子、1个底盘、1个驾驶位...
好了,为了简便,就造这三个吧,先造个爬犁出来...
所以我需要一个大型项目构造者`CarBuilder`:
```go
type CarBuilder struct {
Car *Car
}
func (cb *CarBuilder) GetResult() interface{} {
return cb.Car
}
func (cb *CarBuilder) NewProduct() {
cb.Car = new(Car)
}
func (cb *CarBuilder) BuildWheels() {
cb.Car.Wheels = "build wheels"
}
func (cb *CarBuilder) BuildChassis() {
cb.Car.Chassis = "build chassis"
}
func (cb *CarBuilder) BuildSeat() {
cb.Car.Seat = "build seat"
}
```
这个建造者实现了`Builder`接口:
```go
type Builder interface {
NewProduct() // 创建一个空产品
BuildWheels() // 建造轮子
BuildChassis() // 建造底盘
BuildSeat() // 建造驾驶位
GetResult() interface{} // 获取建造好的产品
}
```
下面要把具体建造者传入指挥者:
```go
type Director struct {
builder Builder
}
func (d *Director) SetBuilder(builder Builder) {
d.builder = builder
}
```
现在指挥者和建造者都已经准备好了,可以进行建造了,调用指挥者的`Generate()` 方法:
```go
func (d *Director) Generate() *Car {
d.builder.NewProduct()
d.builder.BuildChassis()
d.builder.BuildSeat()
d.builder.BuildWheels()
return d.builder.GetResult().(*Car)
}
```
这样,就得到了我们需要的 `Car` 对象:
```go
func main() {
// 创建一个指挥者
director := new(Director)
// 创建建造者
builder := new(CarBuilder)
director.SetBuilder(builder)
car := director.Generate()
car.Show()
}
```
### 总结
上面的代码,是将一个本来就不是很复杂的对象,强行拆分,只是将其中的字段设为最简单的`string` 类型,实际上,这些字段应该是更小的对象结构体,然后还可以继续把这些小结构体继续拆分,拆分为最小单元,这样才是结构最清晰的思路.
本来想举一个应用在实际项目中的栗子的,但是框架还没有写完,这样,先占个坑,等`bingo`框架完成后我会再来补充这一部分.
> 上述代码均放在 [golang-design-patterns](https://github.com/silsuer/golang-design-patterns) 这个仓库中
> 打个广告,推荐一下自己写的 go web框架 [bingo](https://github.com/silsuer/bingo),求star求PR ~