上篇文章,介紹了《大話設(shè)計(jì)模式》的第12章——外觀模式。
本篇,來介紹《大話設(shè)計(jì)模式》的第13章——建造者模式。并通過python代碼實(shí)現(xiàn)示例代碼的功能。
1 建造者模式
建造者模式(Builder):將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
建造者模式的類圖如下:
- Builder:抽象建造類,定義建造一個(gè)產(chǎn)品所需要必要部件。ConcreateBuilder:具體建造類,繼承于抽象建造類,對(duì)抽象建造類中定義的接口進(jìn)行實(shí)現(xiàn),以實(shí)現(xiàn)個(gè)性化特征的產(chǎn)品構(gòu)建。Product:具體產(chǎn)品,具體建造類依賴于具體產(chǎn)品,即建造要根據(jù)產(chǎn)品功能來進(jìn)行建造。Director:指揮者類,控制建造的過程,確保建造過程中必要部件都執(zhí)行了建造。
2 實(shí)例
背景:書中小故事,小菜和大鳥去飯店吃飯,分別點(diǎn)的炒面和炒飯,小菜的炒面吃著還不錯(cuò),大鳥的炒飯味道不夠,蛋也少。大鳥嘗了一下炒面,味道不錯(cuò),就又要了份炒面,結(jié)果,這炒面沒放鹽。。?;厝サ穆飞希篪B感慨,肯德基、麥當(dāng)勞能在中國(guó)發(fā)展的很好,大概是因?yàn)槠渲谱鬟^程規(guī)范嚴(yán)格,而中國(guó)的小吃,比如“魚香肉絲”,不同的店可以吃出各種不同的口味。
啟發(fā):小吃店吃的味道怎么樣,依賴于廚師。聯(lián)想依賴倒轉(zhuǎn)原則:抽象不應(yīng)該依賴細(xì)節(jié),細(xì)節(jié)應(yīng)該依賴于抽象,由于吃的飯菜要依賴于廚師這樣的細(xì)節(jié),飯客就很被動(dòng)。而像KFC那樣,制作流程進(jìn)行抽象,具體放什么配料、烤多長(zhǎng)時(shí)間等細(xì)節(jié)依賴于這個(gè)抽象。
題目:根據(jù)流程的抽象原理,用代碼的形式來實(shí)現(xiàn)用程序畫不同體型的小人。
2.1 版本一:?jiǎn)为?dú)的類
版本一要實(shí)現(xiàn)畫一個(gè)瘦的小人和一個(gè)胖的小人,通過分別定義這兩個(gè)類來實(shí)現(xiàn)所需的功能。
2.1.1 瘦人和胖人類
這里通過Python編程來進(jìn)行實(shí)踐,使用pygame庫中提供畫圖接口進(jìn)行畫圖。
畫一個(gè)廋的小人(ThinPerson),需要畫出頭(一個(gè)橢圓)、身體(一個(gè)矩形)、兩個(gè)胳膊(線))、兩條腿(線)
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)
畫一個(gè)胖的小人(FatPerson),也是類似的。不過這種方式,需要在編寫代碼的時(shí)候不要忘記小人的各個(gè)部分都要有,如果忘記了其中某些項(xiàng),如忘記了畫其中一條腿,最終畫出來的小人就是不完整的。
2.1.2 主函數(shù)
首先,實(shí)例化對(duì)應(yīng)的股票,
然后,就可以調(diào)用對(duì)應(yīng)的買入和賣出的接口了。
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()
畫廋人的效果就是上面的那個(gè)圖,畫胖人的效果,如果忘記了畫其中一條腿,將是下面的效果:
2.2 版本二:建造者模式
為了避免每增加一個(gè)新的不同特點(diǎn)的畫小人的需求在實(shí)現(xiàn)時(shí),可能忘記畫小人的某一部分的問題,可以使用建造者模式。
畫小人使用建造者模式,需要定義一個(gè)抽象類PersonBuilder,并聲明畫小人的各個(gè)部分的接口(聲明為抽象接口,即繼承的子類必須對(duì)接口進(jìn)行對(duì)應(yīng)的實(shí)現(xiàn)),具體不同特征的小人,各個(gè)部分的具體畫法是怎樣的,由具體建造者如畫瘦人的ThinPersonBuilder和畫胖人的FatPersonBuilder來進(jìn)行各自的實(shí)現(xiàn)。
為了能確保不過是畫廋人還是畫胖人,各個(gè)部分都能畫出而不遺漏,還需要一個(gè)指揮者PersonDirector,用它來控制建造過程。控制的原理是由它提供一個(gè)draw_person的接口,其內(nèi)部統(tǒng)一進(jìn)行繪制小人身體的各個(gè)部分。
修改后的代碼如下:
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()
使用建造者模式后,因?yàn)槔L制小人的各個(gè)部分是由指揮者PersonDirector來控制繪制的,因此不會(huì)出現(xiàn)某個(gè)部位的繪制遺漏,如果某個(gè)具體建造者忘記了對(duì)其某個(gè)部分的繪制進(jìn)行重寫,在編譯運(yùn)行時(shí)就會(huì)報(bào)錯(cuò),例如畫胖人時(shí)忘記了畫右腿:
總結(jié)
本篇介紹了設(shè)計(jì)模式中的建造者模式,并通過畫小人的實(shí)例,使用Python編程,來演示建造者模式的使用。
文章推薦