Python 设计模式之建造者模式 Builder Pattern

 #引入建造者模式

肯德基的菜单上有 薯条, 鸡腿,鸡翅,鸡米花,可乐,橙汁,火腿汉堡,至尊虾汉堡,牛肉汉堡 , 鸡肉卷等这些单品,也有很多套餐。

比如

套餐1:鸡翅,至尊虾汉堡,可乐,薯条

套餐2:鸡腿,火腿汉堡,橙汁,薯条

套餐3: 。。。。。

全家桶:。。。。。

这种有各种各样的单品一步一步生成各种套餐, 这种过程称的上建造者模式

 使用多个简单的对象一步一步构建成一个复杂的对象,有点像造房子一样一步步从地基做起到万丈高楼。我想这也是为什么被称呼为建造者模式的原因吧!

 #建造者定义

 Separate the construction of a complex object from its representation so that the same construction process can create different representations.
将一个复杂对象的构建与它的表示进行分离,使得同样的构建过程可以创建不同的表示。

 这个定义里面的 ‘不同的表示’ 意思是不同的产品, 或者是不同的功能。

简单理解:建造者模式(Builder Pattern) 具备两层含义:

  • 构建与表示分离构建 代表对象创建,表示 代表对象行为/方法,也就是对象的创建与行为进行分离(对应到 java 代码,其实就是使用 接口 规定行为,然后由具体的实现类进行构建)。
  • 创建不同的表示:也就是具备同样的行为,但是却由于构建的行为顺序不同或其他原因可以创建出不同的表示。

我们看完上述 建造者模式 的定义,就知道它与 工厂模式 是非常相似的。构建与表示分离创建不同的表示 对于 工厂模式 同样具备。建造者模式 唯一区别于 工厂模式 主要是针对 复杂对象的构建

也就是说,如果是创建简单对象,我们通常都是使用 工厂模式 进行创建;而如果是创建复杂对象,那么此时就可以考虑使用 建造者模式。

#主要解决

当需要构建的产品具备 复杂创建 过程时,可以抽取出共性构建过程,然后交由具体实现类自定义构建流程,使得同样的构建行为可以生产出不同的产品,分离了构建与表示,使构建产品灵活性大大增加。

#使用场景

看到上面的模式定义内容,可以根据内容剥离出这个模式的使用场景

1)需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;

2)隔离复杂对象的创建和使用,并使得相同的构建过程可以创建不同的产品。

 #建造者模式的优点

我在百度文库里看到了这个作者的文章,我喜欢ta的表述,不能复制,我就敲下来放这里了

1)在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建进行解耦,使得相同的创建过程可以创建不同的产品对象

2)每一个具体建造者都是独立的,与其他的具体建造者无关,,因此可以很方便的替换具体建造者或增加具体建造者,用户使用不同的具体建造者可得到不同的产品对象,由于指挥者类针对抽象建造者编程,增加新的具体建造者无需修改原有类库的代码,系统扩展方便,符合开闭原则。在编写代码中,代码复用率是尤为重要的

3)用户可以更为精细的控制产品的创建过程,将复杂的产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程

#建造者模式的缺点

1)建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性较大,例如很多组成部分不相同,则不适合使用建造者模式,因此使用范围受到一定的限制

2)如果产品的内部变化复杂,可能需要很多具体建造者类类实现这种变化,导致系统变得庞大,增加了系统的理解难度和运行成本

#建造者模式 主要包含四种角色:

1)抽象建造者(Builder):主要用于规范产品类的各个组成部分,并提供一个返回完整产品的接口。

2)具体建造者(Concrete Builder):实现 抽象建造者 规定的各个方法,返回一个组件好的具体产品。

3)产品(Product):构建相当复杂的类型,建造者最终创建的产品类型。

4)导演者(Director):指导 建造者(Builder) 以特定行为构建出产品,并将其返回给客户。

总结:理解了 建造者模式 的四种角色,其实就已经掌握了 建造者模式 的真谛:建造者模式 最终返回一个具体的构建复杂的产品;系统中产品可能只有一种类型或多种类型,但对某些产品族来说,它们具备相同的行为,因此对这些共性行为进行抽象,抽离出 抽象建造者(Builder);而对这些行为的具体构建过程,则交由 具体建造者(Concrete Builder) 负责,不同的 具体建造者 会构建出不同表示的产品;而具体要构建出哪种产品,由 导演者(Director) 决定。导演者 会选择不同的 具体建造者,指导它构建出产品。

#注意,也可以静态内部类实现 建造者模式

事实上,在平常的代码中,我们通常都会忽略对象的复杂性,使用 工厂模式 创建对象,而不是 建造者模式。正如上文所讲,工厂模式 和 建造者模式 的作用都是用于创建一个产品对象,而 工厂模式 结构更加简洁直接(没有 Builder 和 Director),因此更常使用。

而 建造者模式,我们更加习惯使用 静态内部类 的方式进行实现,即一个 产品类 内部自动带有一个 具体建造者(Concrete Builder),由它负责该产品的组装创建。不再需要 抽象建造者(Builder) 和 导演者(Director),这样,使得产品与构建之间的联系更加紧密,结构更加紧凑,同时使得 建造者模式 形式更加简洁。

#举个例子

 这个订单系统的例子很容易理解,作者写的有点冗余,不过完全能说明这是一个建造者模式

1class Burger(): 2 """ 3 主食类,价格名字 4 """ 5 name="" 6 price=0.0 7 def getPrice(self): 8 return self.price 9 def setPrice(self,price): 10 self.price=price 11 def getName(self): 12 return self.name 13class cheeseBurger(Burger): 14 """ 15 奶酪汉堡 16 """ 17 def __init__(self): 18 self.name="cheese burger" 19 self.price=10.0 20class spicyChickenBurger(Burger): 21 """ 22 香辣鸡汉堡 23 """ 24 def __init__(self): 25 self.name="spicy chicken burger" 26 self.price=15.0 27 28 29class Snack(): 30 """ 31 小食类,价格以及名字 32 """ 33 name = "" 34 price = 0.0 35 type = "SNACK" 36 def getPrice(self): 37 return self.price 38 def setPrice(self, price): 39 self.price = price 40 def getName(self): 41 return self.name 42class chips(Snack): 43 """ 44 炸薯条 45 """ 46 def __init__(self): 47 self.name = "chips" 48 self.price = 6.0 49class chickenWings(Snack): 50 """ 51 鸡翅 52 """ 53 def __init__(self): 54 self.name = "chicken wings" 55 self.price = 12.0 56 57class Beverage(): 58 """ 59 饮料 60 """ 61 name = "" 62 price = 0.0 63 type = "BEVERAGE" 64 def getPrice(self): 65 return self.price 66 def setPrice(self, price): 67 self.price = price 68 def getName(self): 69 return self.name 70class coke(Beverage): 71 """ 72 可乐 73 """ 74 def __init__(self): 75 self.name = "coke" 76 self.price = 4.0 77class milk(Beverage): 78 """ 79 牛奶 80 """ 81 def __init__(self): 82 self.name = "milk" 83 self.price = 5.0 84 85 86class order(): 87 """ 88 订单对象,一个订单中包含一份主食,一份小食,一份饮料 89 """ 90 burger="" 91 snack="" 92 beverage="" 93 def __init__(self,orderBuilder): 94 self.burger=orderBuilder.bBurger 95 self.snack=orderBuilder.bSnack 96 self.beverage=orderBuilder.bBeverage 97 def show(self): 98 print("Burger:%s"%self.burger.getName()) 99 print("Snack:%s"%self.snack.getName()) 100 print("Beverage:%s"%self.beverage.getName()) 101 102# 建造者 103class orderBuilder(): 104 """ 105 orderBuilder就是建造者模式中所谓的“建造者”, 106 将订单的建造与表示相分离,以达到解耦的目的。 107 在上面订单的构建过程中,如果将order直接通过参数定义好(其构建与表示没有分离), 108 同时在多处进行订单生成,此时需要修改订单内容, 109 则需要一处处去修改,业务风险也就提高了不少。 110 """ 111 bBurger="" 112 bSnack="" 113 bBeverage="" 114 def addBurger(self,xBurger): 115 self.bBurger=xBurger 116 def addSnack(self,xSnack): 117 self.bSnack=xSnack 118 def addBeverage(self,xBeverage): 119 self.bBeverage=xBeverage 120 def build(self): 121 return order(self) 122 123# Director类 124class orderDirector(): 125 """ 126 在建造者模式中,还可以加一个Director类,用以安排已有模块的构造步骤。 127 对于在建造者中有比较严格的顺序要求时,该类会有比较大的用处。 128 """ 129 order_builder="" 130 def __init__(self,order_builder): 131 self.order_builder=order_builder 132 def createOrder(self,burger,snack,beverage): 133 self.order_builder.addBurger(burger) 134 self.order_builder.addSnack(snack) 135 self.order_builder.addBeverage(beverage) 136 return self.order_builder.build() 137 138#场景实现 139if __name__=="__main__": 140 order_builder=orderBuilder() 141 order_builder.addBurger(spicyChickenBurger()) 142 order_builder.addSnack(chips()) 143 order_builder.addBeverage(milk()) 144 order_1=order_builder.build() 145 order_1.show()

#参考

https://www.jianshu.com/p/47329a94f5dc

https://wenku.baidu.com/view/34a8a76cb9f67c1cfad6195f312b3169a451ea99.html

https://segmentfault.com/a/1190000019414444?utm\_source=tag-newest

https://www.jianshu.com/p/9a90ca0fc24f

https://www.cnblogs.com/welan/p/9124081.html

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )