成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

python設(shè)計(jì)模式-工廠方法模式

pubdreamcc / 1845人閱讀

摘要:工廠方法模式可以幫助我們將產(chǎn)品的實(shí)現(xiàn)從使用中解耦。應(yīng)用中使用工廠模式的例子的模塊使用工廠方法模式來(lái)創(chuàng)建表單字段。也使用到了工廠方法模式。中不同數(shù)據(jù)庫(kù)連接部分也用到了工廠方法模式。

題目:假設(shè)你有一個(gè) pizza 店,功能包括下訂單、做 pizza,你的代碼會(huì)如何寫呢?

def order_pizza():
    pizza = Pizza()
    pizza.prepare()
    pizza.bake()
    pizza.cut()
    pizza.box()
    return pizza

但是現(xiàn)在你遇到了一個(gè)問(wèn)題,你的 pizza 店需要更多的 pizza,所以現(xiàn)在你需要增加一些代碼,來(lái)決定適合的 pizza 類型,然后再制造這個(gè) pizza:

def order_pizza(pizza_type):  # 現(xiàn)在把 pizza 的類型傳入 order_pizza()

    # 根據(jù) pizza 類型,我們實(shí)例化正確的具體類,然后將其賦值給 pizza 實(shí)例變量
    if pizza_type == "cheese":
        pizza = CheesePizza()
    elif pizza_type == "greek":
        pizza = GreekPizza()
    elif pizza_type == "pepperoni":
        pizza = PepperoniPizza()
    # 一旦我們有了一個(gè) pizza,需要做一些準(zhǔn)備(搟面皮、加佐料),然后烘烤、切片、裝盒
    pizza.prepare()
    pizza.bake()
    pizza.cut()
    pizza.box()
    return pizza

但是經(jīng)過(guò)幾天的實(shí)踐,你發(fā)現(xiàn)顧客喜歡點(diǎn)的 ClamPizza、Veggie Pizza 而 Greek pizza 并沒(méi)有什么人喜歡,這個(gè)時(shí)候需要修改代碼:

def order_pizza(pizza_type):  # 現(xiàn)在把 pizza 的類型傳入 order_pizza()

    # 根據(jù) pizza 類型,我們實(shí)例化正確的具體類,然后將其賦值給 pizza 實(shí)例變量
    if pizza_type == "cheese":
        pizza = CheesePizza()
    # elif pizza_type == "greek":  # greek pizza 不再出現(xiàn)在菜單
    #     pizza = GreekPizza()
    elif pizza_type == "pepperoni":
        pizza = PepperoniPizza()
    # 新加了 clam pizza 和 veggie pizza
    elif pizza_type == "clam":
        pizza = ClamPizza()
    elif pizza_type == "veggie":
        pizza = VeggiePizza()

    #  一旦我們有了一個(gè) pizza,需要做一些準(zhǔn)備(搟面皮、加佐料),然后烘烤、切片、裝盒
    pizza.prepare()
    pizza.bake()
    pizza.cut()
    pizza.box()
    return pizza

現(xiàn)在你發(fā)現(xiàn)了一個(gè)問(wèn)題, order_pizza() 是在內(nèi)部實(shí)例化了具體的 Pizza 類,并且,order_pizza() 也沒(méi)有對(duì)修改關(guān)閉,以至于每次有了新的 pizza 加入都要修改 order_pizza() 的代碼。這時(shí)一個(gè)比較好的辦法是把創(chuàng)建 Pizza 對(duì)象是抽象出來(lái),修改后的代碼如下:

# 把創(chuàng)建對(duì)象的代碼從 order_pizza 方法中抽離
def create_pizza(pizza_type):
    # 根據(jù) pizza 類型,我們實(shí)例化正確的具體類,然后將其賦值給 pizza 實(shí)例變量
    if pizza_type == "cheese":
        pizza = CheesePizza()
    elif pizza_type == "pepperoni":
        pizza = PepperoniPizza()
    elif pizza_type == "clam":
        pizza = ClamPizza()
    elif pizza_type == "veggie":
        pizza = VeggiePizza()
    return pizza

def order_pizza(pizza_type):  # 現(xiàn)在把 pizza 的類型傳入 order_pizza()
    # 這里使用 create_pizza() 方法創(chuàng)建 pizza 類
    pizza = create_pizza(pizza_type)

    #  一旦我們有了一個(gè) pizza,需要做一些準(zhǔn)備(搟面皮、加佐料),然后烘烤、切片、裝盒
    pizza.prepare()
    pizza.bake()
    pizza.cut()
    pizza.box()
    return pizza
簡(jiǎn)單工廠模式

我們把創(chuàng)建 pizza 對(duì)象的代碼提取到一個(gè)新的方法中,我們稱這個(gè)新的方法叫做工廠。

工廠處理創(chuàng)建對(duì)象的細(xì)節(jié),一旦有了create_pizza,order_pizza() 就成了此對(duì)象的客戶。當(dāng)需要 pizza 時(shí),只需要告訴工廠需要什么類型的 pizza,讓它做一個(gè)即可。

現(xiàn)在 order_pizza() 方法只關(guān)心從工廠得到一個(gè) pizza,這個(gè) pizza 實(shí)現(xiàn)了 Pizza 的接口,所以它可以調(diào)用 prepare()(準(zhǔn)備)、bake()(烘烤)、cut()(切片)、box()(裝盒)

問(wèn):現(xiàn)在你可能會(huì)問(wèn),這段代碼看上去更復(fù)雜了,有什么好處了呢?看上去只是把問(wèn)題搬到另一個(gè)對(duì)象了。

答: 現(xiàn)在看來(lái),order_pizza 只是create_pizza 的一個(gè)客戶,其它客戶(比如pizza 店菜單 PizzaShopMenu)也可以使用這個(gè)工廠來(lái)取得 pizza。把創(chuàng)建 pizza 的代碼包裝進(jìn)一個(gè)類,當(dāng)以后實(shí)現(xiàn)修改時(shí),只需要修改這個(gè)部分代碼即可。

這里我們的工廠create_order() 是一個(gè)簡(jiǎn)單的方法,利用方法定義一個(gè)簡(jiǎn)單工廠的方法通常被稱為簡(jiǎn)單工廠模式簡(jiǎn)單工廠更像是一中編程習(xí)慣而不是設(shè)計(jì)模式)。

重做 PizzaStore 類

上邊的代碼中,order_pizza 是客戶代碼,但是為了讓我們的 pizza 店有更好的擴(kuò)展性,這里我們需要把客戶代碼做一下修改:

class SimplePizzaFactory:

    def create_pizza(self, pizza_type):
        ...
        return pizza

class PizzaStore:
    def order_pizza(self, pizza_type):  # 現(xiàn)在把 pizza 的類型傳入 order_pizza()
        factory = SimplePizzaFactory()
        pizza = factory.create_pizza(pizza_type)
        ...
        return pizza
    
    # 下邊是其他可能用到的方法

這段代碼中,我們把一個(gè)方法(create_pizza)使用類(SimplePizzaFactory)封裝了起來(lái),目的是使工廠可以通過(guò)繼承來(lái)改變創(chuàng)建方法的行為,并且這樣做,也可以提高工廠方法的擴(kuò)展性。

現(xiàn)在來(lái)看一下我們 pizza 店的類圖:

簡(jiǎn)單工廠模式的局限 缺點(diǎn)

由于工廠類集中了所有產(chǎn)品創(chuàng)建邏輯,違反了高內(nèi)聚責(zé)任分配原則,一旦不能正常工作,整個(gè)系統(tǒng)都要受到影響。

系統(tǒng)擴(kuò)展困難,一旦添加新產(chǎn)品就不得不修改工廠邏輯,在產(chǎn)品類型較多時(shí),有可能造成工廠邏輯過(guò)于復(fù)雜,不利于系統(tǒng)的擴(kuò)展和維護(hù)。

使用場(chǎng)景

工廠類負(fù)責(zé)創(chuàng)建的對(duì)象較少

客戶只知道傳入工廠類的參數(shù),對(duì)于如何創(chuàng)建對(duì)象(邏輯)不關(guān)心;客戶端既不需要關(guān)心創(chuàng)建細(xì)節(jié),甚至連類名都不需要記住,只需要知道類型所對(duì)應(yīng)的參數(shù)。

為了突破這些局限,我們接著看一下工廠方法模式

工廠方法模式

現(xiàn)在我們有了一個(gè)新的問(wèn)題,我們創(chuàng)建 pizza 店后,現(xiàn)在有人想要加盟,但我們還想要控制一下 pizza 的制作流程,該如何實(shí)現(xiàn)呢?

首先,要給 pizza 店使用框架,我們所要做的就是把create_pizza()方法放回到PizzaStore類中,不過(guò)這個(gè)方法需要在每個(gè)子類中倒要實(shí)現(xiàn)一次?,F(xiàn)在 PizzaStore代碼為:

class PizzaStore:

    def create_pizza(self, pizza_type):
        # 每個(gè)需要子類實(shí)現(xiàn)的方法都會(huì)拋出NotImplementedError
        # 我們也可以把 PizzaStore 的 metaclass 設(shè)置成 abc.ABCMeta
        # 這樣的話,這個(gè)類就是真正的抽象基類
        raise NotImplementedError()

    def order_pizza(self, pizza_type):  # 現(xiàn)在把 pizza 的類型傳入 order_pizza()

        pizza = self.create_pizza(pizza_type)

        #  一旦我們有了一個(gè) pizza,需要做一些準(zhǔn)備(搟面皮、加佐料),然后烘烤、切片、裝盒
        pizza.prepare()
        pizza.bake()
        pizza.cut()
        pizza.box()
        return pizza

這樣我們就聲明了一個(gè)工廠方法。這個(gè)工廠方法用來(lái)處理對(duì)象的創(chuàng)建,并將這個(gè)創(chuàng)建行為封裝在子類中,這樣客戶程序中關(guān)于父類的代碼就和子類的對(duì)象創(chuàng)建代碼解耦成功。

我們將 create_pizza 放回 PizzaStore 的目的是讓繼承此方法的子類負(fù)責(zé)定義自己的create_pizza() 方法?,F(xiàn)在我們看一下PizzaStore 的子類示意圖:

這里 NYStlyePizzaStoreChicagoStylePizzaStore 需要分別定義自己的 create_pizza 方法。

現(xiàn)在來(lái)看下完整代碼:

#! -*- coding: utf-8 -*-

class Pizza:

    name = None
    dough = None
    sauce = None
    toppings = []

    def prepare(self):
        print("Preparing %s" % self.name)
        print("Tossing dough...")
        print("Adding sauce...")
        print("Adding toppings: ")
        for topping in self.toppings:
            print("  %s" % topping)

    def bake(self):
        print("Bake for 25 minutes at 350")

    def cut(self):
        print("Cutting the pizza into diagonal slices")

    def box(self):
        print("Place pizza in official PizzaStore box")

    def __str__(self):
        return self.name


class NYStyleCheesePizza(Pizza):

    name = "NY Style Sauce and Cheese Pizza"
    dough = "Thin Crust Dough"
    sauce = "Marinara Sauce"
    toppings = ["Grated", "Reggiano", "Cheese"]


class ChicagoStyleCheesePizza(Pizza):

    name = "Chicago Style Deep Dish Cheese Pizza"
    dough = "Extra Thick Crust Dough"
    sauce = "Plum Tomato Sauce"
    toppings = ["Shredded", "Mozzarella", "Cheese"]

    def cut(self):
        print("Cutting the pizza into square slices")


class PizzaStore:
    def create_pizza(self, pizza_type):
        # 每個(gè)需要子類實(shí)現(xiàn)的方法都會(huì)拋出NotImplementedError
        # 我們也可以把 PizzaStore 的 metaclass 設(shè)置成 abc.ABCMeta
        # 這樣的話,這個(gè)類就是真正的抽象基類
        raise NotImplementedError()

    def order_pizza(self, pizza_type):  # 現(xiàn)在把 pizza 的類型傳入 order_pizza()

        pizza = self.create_pizza(pizza_type)

        #  一旦我們有了一個(gè) pizza,需要做一些準(zhǔn)備(搟面皮、加佐料),然后烘烤、切片、裝盒
        pizza.prepare()
        pizza.bake()
        pizza.cut()
        pizza.box()
        return pizza

class NYStylePizzStore(PizzaStore):
    def create_pizza(self, pizza_type):
        # 根據(jù) pizza 類型,我們實(shí)例化正確的具體類,然后將其賦值給 pizza 實(shí)例變量
        if pizza_type == "cheese":
            pizza = NYStyleCheesePizza()
        return pizza


class ChicagoStylePizzaStore(PizzaStore):
    def create_pizza(self, pizza_type):
        # 根據(jù) pizza 類型,我們實(shí)例化正確的具體類,然后將其賦值給 pizza 實(shí)例變量
        if pizza_type == "cheese":
            pizza = ChicagoStyleCheesePizza()
        return pizza


def main():
    nystore = NYStylePizzStore()
    pizza = nystore.order_pizza("cheese")
    print("goodspeed ordered a %s" % pizza)

    print("*" * 100)
    chicago_store = ChicagoStylePizzaStore()
    pizza = chicago_store.order_pizza("cheese")
    print("goodspeed ordered a %s" % pizza)


if __name__ == "__main__":
    main()

這里工廠方法 create_pizza() 直接拋出了NotImplementedError,這樣做事為了強(qiáng)制子類重新實(shí)現(xiàn) create_pizza() 方法,如果不重新實(shí)現(xiàn)就會(huì)拋出NotImplementedError。
當(dāng)然也可以把 PizzaStore 的 metaclass 設(shè)置成 abc.ABCMeta 這樣的話,這個(gè)類就是真正的抽象基類。

現(xiàn)在我們看一下工廠方法模式的類圖:

產(chǎn)品類和創(chuàng)建者類其實(shí)是平行的類的層級(jí)它們的關(guān)系如下圖:

工廠方法模式定義

通過(guò)上文的介紹,我們可以得到工廠方法模式大概的定義:

工廠方法模式中,工廠父類負(fù)責(zé)定義創(chuàng)建產(chǎn)品對(duì)象的公共接口,而工廠子類則負(fù)責(zé)生成具體的產(chǎn)品對(duì)象,這樣做的目的是將產(chǎn)品類的實(shí)例化操作延遲到工廠子類中完成,即通過(guò)工廠子類來(lái)確定究竟應(yīng)該實(shí)例化哪一個(gè)具體產(chǎn)品類。

工廠方法模式能夠封裝具體類型的實(shí)例化,抽象的 Creator 提供了一個(gè)創(chuàng)建對(duì)象的工廠方法。在抽象的 Creator 中,任何其他實(shí)現(xiàn)的方法,都可能使用到這個(gè)方法鎖制造出來(lái)的產(chǎn)品,但只有子類真正實(shí)現(xiàn)這個(gè)工廠方法并創(chuàng)建產(chǎn)品。

下圖是工廠方法模式原理類圖:

工廠方法模式優(yōu)點(diǎn)

工廠方法集中的在一個(gè)地方創(chuàng)建對(duì)象,使對(duì)象的跟蹤變得更容易。

工廠方法模式可以幫助我們將產(chǎn)品的實(shí)現(xiàn)從使用解耦。如果增加產(chǎn)品或者改變產(chǎn)品的實(shí)現(xiàn),Creator 并不會(huì)收到影響。

使用工廠方法模式的另一個(gè)優(yōu)點(diǎn)是在系統(tǒng)中加入新產(chǎn)品時(shí),無(wú)須修改抽象工廠和抽象產(chǎn)品提供的接口,無(wú)須修改客戶端,也無(wú)須修改其他的具體工廠和具體產(chǎn)品,而只要添加一個(gè)具體工廠和具體產(chǎn)品就可以了。這樣,系統(tǒng)的可擴(kuò)展性也就變得非常好,完全符合“開(kāi)閉原則”。

工廠方法可以在必要時(shí)創(chuàng)建新的對(duì)象,從而提高性能和內(nèi)存使用率。若直接實(shí)例化類來(lái)創(chuàng)建對(duì)象,那么每次創(chuàng)建新對(duì)象就需要分配額外的內(nèi)存。

簡(jiǎn)單工廠工廠方法之間的差異

簡(jiǎn)單工廠把全部的事情在一個(gè)地方處理完了(create_pizza),而工廠方法是創(chuàng)建了一個(gè)框架,讓子類去決定如何實(shí)現(xiàn)。比如在工廠方法中,order_pizza() 方法提供了一般的框架用來(lái)創(chuàng)建 pizza,order_pizza() 方法依賴工廠方法創(chuàng)建具體類,并制造出實(shí)際的 pizza。而制造什么樣的 pizza 是通過(guò)繼承 PizzaStore來(lái)實(shí)現(xiàn)的。 但 簡(jiǎn)單工廠 只是把對(duì)象封裝起來(lái),并不具備工廠方法的彈性。

python 應(yīng)用中使用工廠模式的例子

Django 的 forms 模塊使用工廠方法模式來(lái)創(chuàng)建表單字段。WTForm 也使用到了工廠方法模式。sqlalchemy 中不同數(shù)據(jù)庫(kù)連接部分也用到了工廠方法模式。

總結(jié)

工廠方法模式的核心思想是定義一個(gè)用來(lái)創(chuàng)建對(duì)象的公共接口,由工廠而不是客戶來(lái)決定需要被實(shí)例化的類,它通常在構(gòu)造系統(tǒng)整體框架時(shí)被用到。工廠方法模式看上去似乎比較簡(jiǎn)單,但是內(nèi)涵卻極其深刻,抽象、封裝、繼承、委托、多態(tài)等面向?qū)ο笤O(shè)計(jì)中的理論都得到了很好的體現(xiàn),應(yīng)用范圍非常廣泛。

參考

《Head First 設(shè)計(jì)模式》

《精通 python 設(shè)計(jì)模式》

《Python 編程實(shí)戰(zhàn)》

Python設(shè)計(jì)模式系列之三: 創(chuàng)建型Factory Method模式


最后,感謝女朋友支持。

歡迎關(guān)注(April_Louisa) 請(qǐng)我喝芬達(dá)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/40931.html

相關(guān)文章

  • python設(shè)計(jì)模式-抽象工廠模式

    摘要:源碼參考抽象工廠模式抽象工廠模式提供一個(gè)接口,用于創(chuàng)建相關(guān)或依賴對(duì)象的家族,而不需要指定具體類。工廠方法模式和抽象工廠模式如何選擇開(kāi)始的時(shí)候,可以選擇工廠方法模式,因?yàn)樗芎?jiǎn)單只需要繼承,并實(shí)現(xiàn)工廠方法即可。 問(wèn)題:在上一篇 python設(shè)計(jì)模式:工廠方法模式我們嘗試使用工廠方法創(chuàng)建了披薩店,現(xiàn)在為了保證披薩加盟店也能有良好的聲譽(yù),我們需要統(tǒng)一原材料,這個(gè)該如何做呢? 為了確保每家加盟...

    seal_de 評(píng)論0 收藏0
  • Python實(shí)現(xiàn)設(shè)計(jì)模式——工廠模式

    摘要:本文會(huì)用實(shí)現(xiàn)三種工廠模式的簡(jiǎn)單例子,所有代碼都托管在上。工廠方法模式繼承了簡(jiǎn)單工廠模式的優(yōu)點(diǎn)又有所改進(jìn),其不再通過(guò)一個(gè)工廠類來(lái)負(fù)責(zé)所有產(chǎn)品的創(chuàng)建,而是將具體創(chuàng)建工作交給相應(yīng)的子類去做,這使得工廠方法模式可以允許系統(tǒng)能夠更高效的擴(kuò)展。 前言 工廠模式,顧名思義就是我們可以通過(guò)一個(gè)指定的工廠獲得需要的產(chǎn)品,在設(shè)計(jì)模式中主要用于抽象對(duì)象的創(chuàng)建過(guò)程,讓用戶可以指定自己想要的對(duì)象而不必關(guān)心對(duì)象的...

    CrazyCodes 評(píng)論0 收藏0
  • 設(shè)計(jì)模式工廠方法模式

    摘要:通過(guò)工廠方法模式的類圖可以看到,工廠方法模式有四個(gè)要素工廠接口工廠接口是工廠方法模式的核心,與調(diào)用者直接交互用來(lái)提供產(chǎn)品。使用場(chǎng)景創(chuàng)建類模式,在任何需要生成復(fù)雜對(duì)象的地方,都可以使用工廠方法模式。 0x01.定義與類型 定義:定義一個(gè)創(chuàng)建對(duì)象的接口,但讓實(shí)現(xiàn)這個(gè)接口的類來(lái)決定實(shí)例化那個(gè)類,工廠方法讓類的實(shí)例化推遲到子類中進(jìn)行 類型:創(chuàng)建型 uml類圖 showImg(https:/...

    geekidentity 評(píng)論0 收藏0
  • 設(shè)計(jì)模式之抽象工廠模式

    摘要:所謂的產(chǎn)品族,一般或多或少的都存在一定的關(guān)聯(lián),抽象工廠模式就可以在類內(nèi)部對(duì)產(chǎn)品族的關(guān)聯(lián)關(guān)系進(jìn)行定義和描述,而不必專門引入一個(gè)新的類來(lái)進(jìn)行管理。 0x01.定義與類型 定義:抽象工廠模式提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口 無(wú)需指定它們具體的類 類型:創(chuàng)建型 UML showImg(https://segmentfault.com/img/bVbtBp1?w=800&h=862...

    Acceml 評(píng)論0 收藏0
  • python之單例模式工廠模式

    摘要:在工廠方法模式中,我們會(huì)遇到一個(gè)問(wèn)題,當(dāng)產(chǎn)品非常多時(shí),繼續(xù)使用工廠方法模式會(huì)產(chǎn)生非常多的工廠類。從簡(jiǎn)單工廠模式到抽象工廠模式,我們都是在用后一種模式解決前一種模式的缺陷,都是在最大程度降低代碼的耦合性。 單例模式 所謂單例模式,也就是說(shuō)不管什么時(shí)候我們要確保只有一個(gè)對(duì)象實(shí)例存在。很多情況下,整個(gè)系統(tǒng)中只需要存在一個(gè)對(duì)象,所有的信息都從這個(gè)對(duì)象獲取,比如系統(tǒng)的配置對(duì)象,或者是線程池。這些...

    jayce 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<