(轉自精通Python設計模式)Python設計模式之建立型模式——2.建造者模式

來源:互聯網
上載者:User

標籤:github   組成   step   設計   分離   pre   對象   特定   read   

  建造者模式將一個複雜物件的構造過程與其表現分離,這樣,同一個構造過程可用於建立多個不同的表現。

  我們來看個實際的例子,假設我們想要建立一個HMTL頁面產生器,HTML頁面的基本結構(構造組件)通常是一樣的:以<html>開始</html>結束,在HTML部分中有<head>和</head>元素,在head部分中又有<title>和</title>元素,等等;但頁面在表現上可以不同。每個頁面有自己的頁面標題、文本標題以及不同的body內容。此外,頁面通常是經過多個步驟建立完成的:有一個函數添加頁面標題,另一個添加主文本標題,還有一個添加頁尾,等等。僅當一個頁面的結構全部完成後,才能使用一個最終的渲染函數將該頁面展示在用戶端。我們甚至可以更進一步擴充這個HTML產生器,讓它可以產生一些完全不同的HTML頁面。一個頁面可能包含表格,另一個頁面可能包含映像庫,還有一個頁麵包含聯絡表單,等等。

  HTML頁面產生問題可以使用建造者模式來解決。該模式中,有兩個參與者:建造者(builder)和指揮者(director) 。建造者負責建立複雜物件的各個組成部分。在HTML例子中,這些組成部分是頁面標題、文本標題、內容主體及頁尾。指揮者使用一個建造者執行個體控制建造的過程。對於HTML樣本,這是指調用建造者的函數設定頁面標題、文本標題等。使用不同的建造者執行個體讓我們可以建立不同的HTML頁面,而無需變更指揮者的代碼。

  案例

  讓我們來看看如何使用建造者設計模式實現一個比薩訂購的應用。比薩的例子特別有意思,因為準備好一個比薩需經過多步操作,且這些操作要遵從特定順序。要添加調味料,你得先準備生麵糰。要添加配料,你得先添加調味料。並且只有當生麵糰上放了調味料和配料之後才能開始烤比薩餅。此外,每個比薩通常要求的烘焙時間都不一樣,依賴於生麵糰的厚度和使用的配料。

  完整範例程式碼(builder.py)如下:

#!/usr/bin/env python# -*- coding: utf-8 -*-# @Date    : 2018/7/15 9:59# @Author  : Yaheng Wang ([email protected])# @Link    : http://www.wy2160640.github.io# @Version : 1.0from enum import Enumimport timePizzaProgress = Enum(‘PizzaProgress‘, ‘queued preparation baking ready‘)PizzaDough = Enum(‘PizzaDough‘, ‘thin thick‘)PizzaSauce = Enum(‘PizzaSauce‘, ‘tomato creme_fraiche‘)PizzaTopping = Enum(‘PizzaTopping‘, ‘mozzarella double_mozzarella bacon ham mushrooms red_onion oregano‘)STEP_DELAY = 3class Pizza:    def __init__(self, name):        self.name = name        self.dough = None        self.sauce = None        self.topping = []    def __str__(self):        return self.name    def prepare_dough(self, dough):        self.dough = dough        print(‘preparing the {} dough of your {}...‘.format(self.dough.name, self))        time.sleep(STEP_DELAY)        print(‘done with the {} dough‘.format(self.dough.name))class MargaritaBuilder:    def __init__(self):        self.pizza = Pizza(‘margarita‘)        self.progress = PizzaProgress.queued        self.baking_time = 5    def prepare_dough(self):        self.progress = PizzaProgress.preparation        self.pizza.prepare_dough(PizzaDough.thin)    def add_sauce(self):        print(‘adding the tomato sauce to your margarita...‘)        self.pizza.sauce = PizzaSauce.tomato        time.sleep(STEP_DELAY)        print(‘done with the tomato sauce‘)    def add_topping(self):        print(‘adding the topping (double mozzarella, oregano) to your margarita‘)        self.pizza.topping.append([i for i in (PizzaTopping.double_mozzarella, PizzaTopping.oregano)])        time.sleep(STEP_DELAY)        print(‘done with the topping (double mozzarella, oregano)‘)    def bake(self):        self.progress = PizzaProgress.baking        print(‘baking your margarita for {} seconds‘.format(self.baking_time))        time.sleep(self.baking_time)        self.progress = PizzaProgress.ready        print(‘your margarita is ready‘)class CreamyBaconBuilder:    def __init__(self):        self.pizza = Pizza(‘creamy bacon‘)        self.progress = PizzaProgress.queued        self.baking_time = 7    def prepare_dough(self):        self.progress = PizzaProgress.preparation        self.pizza.prepare_dough(PizzaDough.thick)    def add_sauce(self):        print(‘adding the creme fraiche sauce to your creamy bacon‘)        self.pizza.sauce = PizzaSauce.creme_fraiche        time.sleep(STEP_DELAY)        print(‘done with the creme fraiche sauce‘)    def add_topping(self):        print(‘adding the topping (mozzarella, bacon, ham, mushrooms, red onion, oregano) to your creamy bacon‘)        self.pizza.topping.append([t for t in (PizzaTopping.mozzarella, PizzaTopping.bacon, PizzaTopping.ham, PizzaTopping.mushrooms, PizzaTopping.red_onion, PizzaTopping.oregano)])        time.sleep(STEP_DELAY)        print(‘done with the topping (mozzarella, bacon, ham, mushroom, red onion, oregano)‘)    def bake(self):        self.progress = PizzaProgress.baking        print(‘baking your creamy bacon for {} seconds‘.format(self.baking_time))        time.sleep(self.baking_time)        self.progress = PizzaProgress.ready        print(‘your creamy bacon is ready‘)class Waiter:    def __init__(self):        self.builder = None    def construct_pizza(self, builder):        self.builder = builder        [step() for step in (builder.prepare_dough, builder.add_sauce, builder.add_topping, builder.bake)]    @property    def pizza(self):        return self.builder.pizzadef validate_style(builders):    try:        pizza_style = input(‘What pizza would you like, [m]argarita or [c]reamy bacon?‘)        builder = builders[pizza_style]()        valid_input = True    except KeyError as err:        print(‘Sorry, only margarita (key m) and creamy bacon (key c) are available‘)        return (False, None)    return (True, builder)def main():    builders = dict(m=MargaritaBuilder, c=CreamyBaconBuilder)    valid_input = False    while not valid_input:        valid_input, builder = validate_style(builders)    print()    waiter = Waiter()    waiter.construct_pizza(builder)    pizza = waiter.pizza    print()    print(‘Enjoy your {}!‘.format(pizza))if __name__ == ‘__main__‘:    main()

   小結

  在以下幾種情況下,與原廠模式相比,建造者模式是更好的選擇。

    1.想要建立一個複雜物件(對象由多個部分構成,且對象的建立要經過多個不同的步驟也許還需要遵從特定的順序)

    2.要求一個對象能有不同的表現,並希望將對象的構造與表現解耦

    3.想要在某個時間點建立對象,但在稍後的時間點再訪問

(轉自精通Python設計模式)Python設計模式之建立型模式——2.建造者模式

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.