作为一个打工仔,在外面辛苦了一年,李力终于要回家过年了。李力给他的小侄子买了两套积木游戏玩具。小侄子玩的不亦乐乎,小侄子把四个轮子、一个车身、一个发动机和一个方向盘拼装成了一辆车。用一间客厅、两个卧室、一间书房、一间厨房、一个花园和一堵围墙搭建了一个庄园......
一、用代码来模拟生活
from abc import ABCMeta, abstractmethod
class Toy(metaclass=ABCMeta):
"""玩具"""
def __init__(self, name):
self._name = name
self.__components = []
def getName(self):
return self._name
def addComponent(self, component, count=1, unit="个"):
self.__components.append([component, count, unit])
print("%s 增加了 %d %s%s" % (self._name, count, unit, component))
@abstractmethod
def feature(self):
pass
class Car(Toy):
"""小车"""
def feature(self):
print("我是%s, 我可以快速奔跑......" % self._name)
class Manor(Toy):
"""庄园"""
def feature(self):
print("我是%s, 我可供观赏。也可用来游玩!" % self._name)
class ToyBuilder:
"""玩具构建者"""
def buildCar(self):
car = Car("迷你小车")
print("正在构建%s......" % car.getName())
car.addComponent("轮子", 4)
car.addComponent("车身", 1)
car.addComponent("发动机", 1)
car.addComponent("方向盘")
return car
def buildManor(self):
manor = Manor("淘淘小庄园")
print("正在构建 %s......" % manor.getName())
manor.addComponent("客厅", 1, "间")
manor.addComponent("卧室", 1, "间")
manor.addComponent("书房", 1, "间")
manor.addComponent("厨房", 1, "间")
manor.addComponent("花园", 1, "个")
manor.addComponent("围墙", 1, "堵")
return manor
if __name__ == "__main__":
builder = ToyBuilder()
car = builder.buildCar()
car.feature()
print("\n")
mannor = builder.buildManor()
mannor.feature()
用golang来演示:
package main
import "fmt"
type component struct {
name string
count int
unit string
}
type ToyInterface interface {
getName() string
addComponent(c component)
feature()
}
type Toy struct {
name string
components []component
}
func (t Toy) getName() string {
return t.name
}
func (t Toy) addComponent(c component) {
t.components = append(t.components, c)
fmt.Printf("%s 增加了 %d %s %s \n", t.name, c.count, c.unit, c.name)
}
func (t Toy) feature() {
fmt.Println("我是玩具......")
}
type Car struct {
Toy
}
func (c Car) feature() {
fmt.Printf("我是%s,我可以快速奔跑......\n", c.name)
}
type Manor struct {
Toy
}
func (m Manor) feature() {
fmt.Printf("我是%s,我可供欣赏,也可用来游玩!", m.name)
}
type ToyBuilder struct {
}
func (t ToyBuilder) buildCar() ToyInterface {
car := Car{Toy{
name: "迷你小车",
components: make([]component, 0, 10),
}}
fmt.Printf("正在构建%s......\n", car.getName())
c1 := component{
name: "轮子",
count: 4,
unit: "个",
}
car.addComponent(c1)
c2 := component{
name: "车身",
count: 1,
unit: "个",
}
car.addComponent(c2)
c3 := component{
name: "发动机",
count: 1,
unit: "个",
}
car.addComponent(c3)
c4 := component{
name: "方向盘",
count: 1,
unit: "个",
}
car.addComponent(c4)
return car
}
func (t ToyBuilder) buildManor() ToyInterface {
manor := Manor{Toy{
name: "淘淘小庄园",
components: make([]component, 5, 10),
}}
fmt.Printf("正在构建%s......\n", manor.getName())
c1 := component{
name: "客厅",
count: 1,
unit: "间",
}
manor.addComponent(c1)
c2 := component{
name: "卧室",
count: 1,
unit: "间",
}
manor.addComponent(c2)
c3 := component{
name: "书房",
count: 1,
unit: "间",
}
manor.addComponent(c3)
c4 := component{
name: "厨房",
count: 1,
unit: "间",
}
manor.addComponent(c4)
c5 := component{
name: "花园",
count: 1,
unit: "个",
}
manor.addComponent(c5)
c6 := component{
name: "围墙",
count: 1,
unit: "堵",
}
manor.addComponent(c6)
return manor
}
func main() {
builder := ToyBuilder{}
car := builder.buildCar()
car.feature()
fmt.Println()
mannor := builder.buildManor()
mannor.feature()
}
二、设计思想
构建顾名思义就是把各种部件通过一定的方式和流程构造成一个成品的过程。在程序中,我们将这一过程称为构建模式(英文叫Builder Pattern,不同的书籍和资料翻译各有不同,有的也叫建造者模式或生成器模式)。
构建模式的核心思想是:将产品的创建过程与产品本身分离开来,使得创建过程更加清晰,能够更加精确地控制复杂对象的创建过程,让使用者可以用相同的创建过程创建不同的产品。
三、比较
3.1 与工厂模式的区别
工厂模式关注的是整个产品(整体对象)的生成,即成品的生成;而构建模式关注的是产品的创建过程和细节,一步一步地由各个子部件构建为一个成品。
比如要创建一辆汽车,如果用工厂模式,直接就创建一辆有车身、轮胎、发动机的能用的汽车。如果用构建模式,则需要由车身、轮胎、发动机一步一步地组装成一辆汽车。
3.2与组合模式的区别
组合模式关注的是“整体-部分”的关系,也就是关注对象的内部组成结构,那么它与构建模式又有什么区别与联系呢?
区别:组合模式关注的是对象内部的组成结构,强调的是部分与整体的关系。构建模式关注的是对象的创建过程,即由一个一个的子部件构建一个成品的过程。
联系:组合模式和构建模式其实也经常被一起使用。还是以组装电脑为例,组合模式和构建模式一起使用。
组装电脑的时候,内存卡(Memory Card)、硬盘(Hard Disk)、核心处理器(CPU)、电池(Battery)、风扇(Fan)都是独立的电子元件,而主板(Mainboard)和机箱(Computer Case)都是由子元件组成的。我们的ComputerBuilder就是构建者,负责整个电脑的组装过程:先把内存卡、硬盘、“CPU组装在主板上,再把主板、电池、风扇组装在机箱里,最后连接鼠标、键盘、显示器,就构成了一台完整的台式电脑。
四、升级版
如果Toy不只有车(car)和庄园(Manor),还有飞机、坦克、摩天轮、过山车等,而且不只造一辆车和一个庄园,数量由用户自己定。那么builder就会变得越来越臃肿,那么就需要进行升级。![](https://img.haomeiwen.com/i3825186/be88d0101586d0db.png)
Product是产品的抽象类(基类),ProductA和ProductB是具体的产品。Builder是抽象构建类,ProductABuilder和ProductBBuilder是对应产品的具体构建类,而BuilderManager是构建类的管理类(很多资料和书籍中叫它导演类(Director)),负责管理每一种产品的创建数量和创建顺序。
package main
import "fmt"
// 组件
type component struct {
name string
count int
unit string
}
type ToyInterface interface {
getName() string
addComponent(c component)
feature()
}
// Toy 玩具
type Toy struct {
name string
components []component
}
func (t Toy) getName() string {
return t.name
}
func (t Toy) addComponent(c component) {
t.components = append(t.components, c)
fmt.Printf("%s 增加了 %d %s %s \n", t.name, c.count, c.unit, c.name)
}
func (t Toy) feature() {
fmt.Println("我是玩具......")
}
// Car 小车
type Car struct {
Toy
}
func (c Car) feature() {
fmt.Printf("我是%s,我可以快速奔跑......\n", c.name)
}
// Manor 庄园
type Manor struct {
Toy
}
func (m Manor) feature() {
fmt.Printf("我是%s,我可供欣赏,也可用来游玩!", m.name)
}
type ToyBuilderInterface interface {
buildProduct() ToyInterface
}
// ToyBuilder 玩具构建者
type ToyBuilder struct {
}
func (t ToyBuilder) buildProduct() ToyInterface {
return Toy{}
}
// CarBuilder 车的构建类
type CarBuilder struct {
ToyBuilder
}
func (t CarBuilder) buildProduct() ToyInterface {
car := Car{Toy{
name: "迷你小车",
components: make([]component, 0, 10),
}}
fmt.Printf("正在构建%s......\n", car.getName())
c1 := component{
name: "轮子",
count: 4,
unit: "个",
}
car.addComponent(c1)
c2 := component{
name: "车身",
count: 1,
unit: "个",
}
car.addComponent(c2)
c3 := component{
name: "发动机",
count: 1,
unit: "个",
}
car.addComponent(c3)
c4 := component{
name: "方向盘",
count: 1,
unit: "个",
}
car.addComponent(c4)
return car
}
// ManorBuilder 庄园的构建类
type ManorBuilder struct {
}
func (t ManorBuilder) buildProduct() ToyInterface {
manor := Manor{Toy{
name: "淘淘小庄园",
components: make([]component, 5, 10),
}}
fmt.Printf("正在构建%s......\n", manor.getName())
c1 := component{
name: "客厅",
count: 1,
unit: "间",
}
manor.addComponent(c1)
c2 := component{
name: "卧室",
count: 1,
unit: "间",
}
manor.addComponent(c2)
c3 := component{
name: "书房",
count: 1,
unit: "间",
}
manor.addComponent(c3)
c4 := component{
name: "厨房",
count: 1,
unit: "间",
}
manor.addComponent(c4)
c5 := component{
name: "花园",
count: 1,
unit: "个",
}
manor.addComponent(c5)
c6 := component{
name: "围墙",
count: 1,
unit: "堵",
}
manor.addComponent(c6)
return manor
}
// BuilderMgr 构建类的管理类
type BuilderMgr struct {
carBuilder CarBuilder
manorBuilder ManorBuilder
}
func (b BuilderMgr) buildCar(num int) []ToyInterface {
var products []ToyInterface
for i := 0; i < num; i++ {
car := b.carBuilder.buildProduct()
products = append(products, car)
fmt.Printf("建造完成第%d辆%s", i+1, car.getName())
}
return products
}
func (b BuilderMgr) buildManor(num int) []ToyInterface {
var products []ToyInterface
for i := 0; i < num; i++ {
manor := b.manorBuilder.buildProduct()
products = append(products, manor)
fmt.Printf("建造完成第%d辆%s\n", i+1, manor.getName())
}
return products
}
func main() {
builderMgr := BuilderMgr{carBuilder: CarBuilder{ToyBuilder{}}}
builderMgr.buildCar(4)
fmt.Println()
builderMgr.buildManor(2)
}
运行结果:
正在构建迷你小车......
迷你小车 增加了 4 个 轮子
迷你小车 增加了 1 个 车身
迷你小车 增加了 1 个 发动机
迷你小车 增加了 1 个 方向盘
建造完成第1辆迷你小车正在构建迷你小车......
迷你小车 增加了 4 个 轮子
迷你小车 增加了 1 个 车身
迷你小车 增加了 1 个 发动机
迷你小车 增加了 1 个 方向盘
建造完成第2辆迷你小车正在构建迷你小车......
迷你小车 增加了 4 个 轮子
迷你小车 增加了 1 个 车身
迷你小车 增加了 1 个 发动机
迷你小车 增加了 1 个 方向盘
建造完成第3辆迷你小车正在构建迷你小车......
迷你小车 增加了 4 个 轮子
迷你小车 增加了 1 个 车身
迷你小车 增加了 1 个 发动机
迷你小车 增加了 1 个 方向盘
建造完成第4辆迷你小车
正在构建淘淘小庄园......
淘淘小庄园 增加了 1 间 客厅
淘淘小庄园 增加了 1 间 卧室
淘淘小庄园 增加了 1 间 书房
淘淘小庄园 增加了 1 间 厨房
淘淘小庄园 增加了 1 个 花园
淘淘小庄园 增加了 1 堵 围墙
建造完成第1辆淘淘小庄园
正在构建淘淘小庄园......
淘淘小庄园 增加了 1 间 客厅
淘淘小庄园 增加了 1 间 卧室
淘淘小庄园 增加了 1 间 书房
淘淘小庄园 增加了 1 间 厨房
淘淘小庄园 增加了 1 个 花园
淘淘小庄园 增加了 1 堵 围墙
建造完成第2辆淘淘小庄园
4.1 模型说明
1.设计要点
构建模式(升级版)中主要有三个角色,在设计构建模式时要找到并区分这些角色。
(1)产品(Product):即你要构建的对象。
(2)构建者(Builder):构建模式的核心类,负责产品的构建过程。
(3)指挥者(BuilderManager):构建的管理类,负责管理每一种产品的创建数量和创建顺序。
2.构建模式的优缺点
优点:
(1)将产品(对象)的创建过程与产品(对象)本身分离开来,让使用方(调用者)可以用相同的创建过程创建不同的产品(对象)。
(2)将对象的创建过程单独分解出来,使得创建过程更加清晰,能够更加精确地控制复杂对象的创建过程。
(3)针对升级版的构建模式,每一个具体构建者都相对独立,而与其他的具体构建者无关,因此可以很方便地替换具体构建者或增加新的具体构建者。
缺点:
(1)增加了很多创建类,如果产品的类型和种类比较多,将会增加很多类,“使整个系统变得更加庞杂。
(2)产品之间的结构相差很大时,构建模式将很难适应。
五、应用场景
(1)产品(对象)的创建过程比较复杂,希望将产品的创建过程和它本身的功能分离开来。
(2)产品有很多种类,每个种类之间内部结构比较类似,但有很多差异;不同的创建顺序或不同的组合方式,将创建不同的产品。
资料:
人人都懂设计模式:从生活中领悟设计模式:Python实现
网友评论