上篇文章,介绍了《大话设计模式》的第12章——外观模式。
本篇,来介绍《大话设计模式》的第13章——建造者模式。并通过python代码实现示例代码的功能。
1 建造者模式
建造者模式(Builder):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式的类图如下:
- Builder:抽象建造类,定义建造一个产品所需要必要部件。ConcreateBuilder:具体建造类,继承于抽象建造类,对抽象建造类中定义的接口进行实现,以实现个性化特征的产品构建。Product:具体产品,具体建造类依赖于具体产品,即建造要根据产品功能来进行建造。Director:指挥者类,控制建造的过程,确保建造过程中必要部件都执行了建造。
2 实例
背景:书中小故事,小菜和大鸟去饭店吃饭,分别点的炒面和炒饭,小菜的炒面吃着还不错,大鸟的炒饭味道不够,蛋也少。大鸟尝了一下炒面,味道不错,就又要了份炒面,结果,这炒面没放盐。。。回去的路上,大鸟感慨,肯德基、麦当劳能在中国发展的很好,大概是因为其制作过程规范严格,而中国的小吃,比如“鱼香肉丝”,不同的店可以吃出各种不同的口味。
启发:小吃店吃的味道怎么样,依赖于厨师。联想依赖倒转原则:抽象不应该依赖细节,细节应该依赖于抽象,由于吃的饭菜要依赖于厨师这样的细节,饭客就很被动。而像KFC那样,制作流程进行抽象,具体放什么配料、烤多长时间等细节依赖于这个抽象。
题目:根据流程的抽象原理,用代码的形式来实现用程序画不同体型的小人。
2.1 版本一:单独的类
版本一要实现画一个瘦的小人和一个胖的小人,通过分别定义这两个类来实现所需的功能。
2.1.1 瘦人和胖人类
这里通过Python编程来进行实践,使用pygame库中提供画图接口进行画图。
画一个廋的小人(ThinPerson),需要画出头(一个椭圆)、身体(一个矩形)、两个胳膊(线))、两条腿(线)
import pygame, sys
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
pygame.init()
screen = pygame.display.set_mode((200, 200))
screen.fill(WHITE)
class ThinPerson:
def draw_person(self):
pygame.draw.ellipse(screen,BLUE,(50,20,30,30),1)
pygame.draw.rect(screen,BLUE,(60, 50, 10, 50),1)
pygame.draw.line(screen,BLUE,(60, 50),(40, 100),1)
pygame.draw.line(screen,BLUE,(70, 50),(90, 100),1)
pygame.draw.line(screen,BLUE,(60, 100),(45, 150),1)
pygame.draw.line(screen,BLUE,(70, 100),(85, 150),1)
class FatPerson:
def draw_person(self):
pygame.draw.ellipse(screen,BLUE,(50,20,30,30),1)
pygame.draw.ellipse(screen,BLUE,(45,50,40,50),1)
pygame.draw.line(screen,BLUE,(50, 50),(30, 100),1)
pygame.draw.line(screen,BLUE,(80, 50),(100, 100),1)
pygame.draw.line(screen,BLUE,(60, 100),(45, 150),1)
#pygame.draw.line(screen,BLUE,(70, 100),(85, 150),1)
画一个胖的小人(FatPerson),也是类似的。不过这种方式,需要在编写代码的时候不要忘记小人的各个部分都要有,如果忘记了其中某些项,如忘记了画其中一条腿,最终画出来的小人就是不完整的。
2.1.2 主函数
首先,实例化对应的股票,
然后,就可以调用对应的买入和卖出的接口了。
thinPerson = ThinPerson()
thinPerson.draw_person()
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
画廋人的效果就是上面的那个图,画胖人的效果,如果忘记了画其中一条腿,将是下面的效果:
2.2 版本二:建造者模式
为了避免每增加一个新的不同特点的画小人的需求在实现时,可能忘记画小人的某一部分的问题,可以使用建造者模式。
画小人使用建造者模式,需要定义一个抽象类PersonBuilder,并声明画小人的各个部分的接口(声明为抽象接口,即继承的子类必须对接口进行对应的实现),具体不同特征的小人,各个部分的具体画法是怎样的,由具体建造者如画瘦人的ThinPersonBuilder和画胖人的FatPersonBuilder来进行各自的实现。
为了能确保不过是画廋人还是画胖人,各个部分都能画出而不遗漏,还需要一个指挥者PersonDirector,用它来控制建造过程。控制的原理是由它提供一个draw_person的接口,其内部统一进行绘制小人身体的各个部分。
修改后的代码如下:
class PersonBuilder(ABC):
@abstractmethod
def build_head(self):
pass
@abstractmethod
def build_body(self):
pass
@abstractmethod
def build_arm_left(self):
pass
@abstractmethod
def build_arm_right(self):
pass
@abstractmethod
def build_leg_left(self):
pass
@abstractmethod
def build_leg_right(self):
pass
class PersonDirector():
def __init__(self,personBuilder):
self.pb = personBuilder
def draw_person(self):
self.pb.build_head()
self.pb.build_body()
self.pb.build_arm_left()
self.pb.build_arm_right()
self.pb.build_leg_left()
self.pb.build_leg_right()
class ThinPersonBuilder(PersonBuilder):
def build_head(self):
pygame.draw.ellipse(screen,BLUE,(50,20,30,30),1)
def build_body(self):
pygame.draw.rect(screen,BLUE,(60, 50, 10, 50),1)
def build_arm_left(self):
pygame.draw.line(screen,BLUE,(60, 50),(40, 100),1)
def build_arm_right(self):
pygame.draw.line(screen,BLUE,(70, 50),(90, 100),1)
def build_leg_left(self):
pygame.draw.line(screen,BLUE,(60, 100),(45, 150),1)
def build_leg_right(self):
pygame.draw.line(screen,BLUE,(70, 100),(85, 150),1)
class FatPersonBuilder(PersonBuilder):
def build_head(self):
pygame.draw.ellipse(screen,BLUE,(50,20,30,30),1)
def build_body(self):
pygame.draw.ellipse(screen,BLUE,(45,50,40,50),1)
def build_arm_left(self):
pygame.draw.line(screen,BLUE,(50, 50),(30, 100),1)
def build_arm_right(self):
pygame.draw.line(screen,BLUE,(80, 50),(100, 100),1)
def build_leg_left(self):
pygame.draw.line(screen,BLUE,(60, 100),(45, 150),1)
"""
def build_leg_right(self):
pygame.draw.line(screen,BLUE,(70, 100),(85, 150),1)
"""
thinPerson = ThinPersonBuilder()
#fatPerson = FatPersonBuilder()
personDirector = PersonDirector(thinPerson)
personDirector.draw_person()
使用建造者模式后,因为绘制小人的各个部分是由指挥者PersonDirector来控制绘制的,因此不会出现某个部位的绘制遗漏,如果某个具体建造者忘记了对其某个部分的绘制进行重写,在编译运行时就会报错,例如画胖人时忘记了画右腿:
总结
本篇介绍了设计模式中的建造者模式,并通过画小人的实例,使用Python编程,来演示建造者模式的使用。
文章推荐