日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python工厂模式 django_python设计模式-工厂方法模式

發布時間:2024/4/17 python 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python工厂模式 django_python设计模式-工厂方法模式 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

def order_pizza():

pizza = Pizza()

pizza.prepare()

pizza.bake()

pizza.cut()

pizza.box()

return pizza復制代碼

但是現在你遇到了一個問題,你的 pizza 店需要更多的 pizza,所以現在你需要增加一些代碼,來決定適合的 pizza 類型,然后再制造這個 pizza:

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

# 根據 pizza 類型,我們實例化正確的具體類,然后將其賦值給 pizza 實例變量

if pizza_type == 'cheese':

pizza = CheesePizza()

elif pizza_type == 'greek':

pizza = GreekPizza()

elif pizza_type == 'pepperoni':

pizza = PepperoniPizza()

# 一旦我們有了一個 pizza,需要做一些準備(搟面皮、加佐料),然后烘烤、切片、裝盒

pizza.prepare()

pizza.bake()

pizza.cut()

pizza.box()

return pizza復制代碼

但是經過幾天的實踐,你發現顧客喜歡點的 ClamPizza、Veggie Pizza 而 Greek pizza 并沒有什么人喜歡,這個時候需要修改代碼:

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

# 根據 pizza 類型,我們實例化正確的具體類,然后將其賦值給 pizza 實例變量

if pizza_type == 'cheese':

pizza = CheesePizza()

# elif pizza_type == 'greek': # greek pizza 不再出現在菜單

# pizza = GreekPizza()

elif pizza_type == 'pepperoni':

pizza = PepperoniPizza()

# 新加了 clam pizza 和 veggie pizza

elif pizza_type == 'clam':

pizza = ClamPizza()

elif pizza_type == 'veggie':

pizza = VeggiePizza()

# 一旦我們有了一個 pizza,需要做一些準備(搟面皮、加佐料),然后烘烤、切片、裝盒

pizza.prepare()

pizza.bake()

pizza.cut()

pizza.box()

return pizza復制代碼

現在你發現了一個問題, order_pizza() 是在內部實例化了具體的 Pizza 類,并且,order_pizza() 也沒有對修改關閉,以至于每次有了新的 pizza 加入都要修改 order_pizza() 的代碼。這時一個比較好的辦法是把創建 Pizza 對象是抽象出來,修改后的代碼如下:

# 把創建對象的代碼從 order_pizza 方法中抽離

def create_pizza(pizza_type):

# 根據 pizza 類型,我們實例化正確的具體類,然后將其賦值給 pizza 實例變量

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): # 現在把 pizza 的類型傳入 order_pizza()

# 這里使用 create_pizza() 方法創建 pizza 類

pizza = create_pizza(pizza_type)

# 一旦我們有了一個 pizza,需要做一些準備(搟面皮、加佐料),然后烘烤、切片、裝盒

pizza.prepare()

pizza.bake()

pizza.cut()

pizza.box()

return pizza復制代碼

簡單工廠模式

我們把創建 pizza 對象的代碼提取到一個新的方法中,我們稱這個新的方法叫做工廠。

工廠處理創建對象的細節,一旦有了create_pizza,order_pizza() 就成了此對象的客戶。當需要 pizza 時,只需要告訴工廠需要什么類型的 pizza,讓它做一個即可。

現在 order_pizza() 方法只關心從工廠得到一個 pizza,這個 pizza 實現了 Pizza 的接口,所以它可以調用 prepare()(準備)、bake()(烘烤)、cut()(切片)、box()(裝盒)

問:現在你可能會問,這段代碼看上去更復雜了,有什么好處了呢?看上去只是把問題搬到另一個對象了。

答: 現在看來,order_pizza 只是create_pizza 的一個客戶,其它客戶(比如pizza 店菜單 PizzaShopMenu)也可以使用這個工廠來取得 pizza。把創建 pizza 的代碼包裝進一個類,當以后實現修改時,只需要修改這個部分代碼即可。

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

重做 PizzaStore 類

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

class SimplePizzaFactory:

def create_pizza(self, pizza_type):

...

return pizza

class PizzaStore:

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

factory = SimplePizzaFactory()

pizza = factory.create_pizza(pizza_type)

...

return pizza

# 下邊是其他可能用到的方法復制代碼

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

現在來看一下我們 pizza 店的類圖:

pizza店類圖

簡單工廠模式的局限

缺點

由于工廠類集中了所有產品創建邏輯,違反了高內聚責任分配原則,一旦不能正常工作,整個系統都要受到影響。

系統擴展困難,一旦添加新產品就不得不修改工廠邏輯,在產品類型較多時,有可能造成工廠邏輯過于復雜,不利于系統的擴展和維護。

使用場景

工廠類負責創建的對象較少

客戶只知道傳入工廠類的參數,對于如何創建對象(邏輯)不關心;客戶端既不需要關心創建細節,甚至連類名都不需要記住,只需要知道類型所對應的參數。

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

工廠方法模式

現在我們有了一個新的問題,我們創建 pizza 店后,現在有人想要加盟,但我們還想要控制一下 pizza 的制作流程,該如何實現呢?

首先,要給 pizza 店使用框架,我們所要做的就是把create_pizza()方法放回到PizzaStore類中,不過這個方法需要在每個子類中倒要實現一次。現在 PizzaStore代碼為:

class PizzaStore:

def create_pizza(self, pizza_type):

# 每個需要子類實現的方法都會拋出NotImplementedError

# 我們也可以把 PizzaStore 的 metaclass 設置成 abc.ABCMeta

# 這樣的話,這個類就是真正的抽象基類

raise NotImplementedError()

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

pizza = self.create_pizza(pizza_type)

# 一旦我們有了一個 pizza,需要做一些準備(搟面皮、加佐料),然后烘烤、切片、裝盒

pizza.prepare()

pizza.bake()

pizza.cut()

pizza.box()

return pizza復制代碼

這樣我們就聲明了一個工廠方法。這個工廠方法用來處理對象的創建,并將這個創建行為封裝在子類中,這樣客戶程序中關于父類的代碼就和子類的對象創建代碼解耦成功。

我們將 create_pizza 放回 PizzaStore 的目的是讓繼承此方法的子類負責定義自己的create_pizza() 方法。現在我們看一下PizzaStore 的子類示意圖:

這里 NYStlyePizzaStore 和 ChicagoStylePizzaStore 需要分別定義自己的 create_pizza 方法。

現在來看下完整代碼:

#! -*- 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):

# 每個需要子類實現的方法都會拋出NotImplementedError

# 我們也可以把 PizzaStore 的 metaclass 設置成 abc.ABCMeta

# 這樣的話,這個類就是真正的抽象基類

raise NotImplementedError()

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

pizza = self.create_pizza(pizza_type)

# 一旦我們有了一個 pizza,需要做一些準備(搟面皮、加佐料),然后烘烤、切片、裝盒

pizza.prepare()

pizza.bake()

pizza.cut()

pizza.box()

return pizza

class NYStylePizzStore(PizzaStore):

def create_pizza(self, pizza_type):

# 根據 pizza 類型,我們實例化正確的具體類,然后將其賦值給 pizza 實例變量

if pizza_type == 'cheese':

pizza = NYStyleCheesePizza()

return pizza

class ChicagoStylePizzaStore(PizzaStore):

def create_pizza(self, pizza_type):

# 根據 pizza 類型,我們實例化正確的具體類,然后將其賦值給 pizza 實例變量

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,這樣做事為了強制子類重新實現 create_pizza() 方法,如果不重新實現就會拋出NotImplementedError。

當然也可以把 PizzaStore 的 metaclass 設置成 abc.ABCMeta 這樣的話,這個類就是真正的抽象基類。

現在我們看一下工廠方法模式的類圖:

工廠方法模式類圖

產品類和創建者類其實是平行的類的層級它們的關系如下圖:

工廠方法模式定義

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

在工廠方法模式中,工廠父類負責定義創建產品對象的公共接口,而工廠子類則負責生成具體的產品對象,這樣做的目的是將產品類的實例化操作延遲到工廠子類中完成,即通過工廠子類來確定究竟應該實例化哪一個具體產品類。

工廠方法模式能夠封裝具體類型的實例化,抽象的 Creator 提供了一個創建對象的工廠方法。在抽象的 Creator 中,任何其他實現的方法,都可能使用到這個方法鎖制造出來的產品,但只有子類真正實現這個工廠方法并創建產品。

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

工廠方法模式類圖

工廠方法模式優點

工廠方法集中的在一個地方創建對象,使對象的跟蹤變得更容易。

工廠方法模式可以幫助我們將產品的實現從使用中解耦。如果增加產品或者改變產品的實現,Creator 并不會收到影響。

使用工廠方法模式的另一個優點是在系統中加入新產品時,無須修改抽象工廠和抽象產品提供的接口,無須修改客戶端,也無須修改其他的具體工廠和具體產品,而只要添加一個具體工廠和具體產品就可以了。這樣,系統的可擴展性也就變得非常好,完全符合“開閉原則”。

工廠方法可以在必要時創建新的對象,從而提高性能和內存使用率。若直接實例化類來創建對象,那么每次創建新對象就需要分配額外的內存。

簡單工廠和工廠方法之間的差異

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

python 應用中使用工廠模式的例子

Django 的 forms 模塊使用工廠方法模式來創建表單字段。WTForm 也使用到了工廠方法模式。sqlalchemy 中不同數據庫連接部分也用到了工廠方法模式。

總結

工廠方法模式的核心思想是定義一個用來創建對象的公共接口,由工廠而不是客戶來決定需要被實例化的類,它通常在構造系統整體框架時被用到。工廠方法模式看上去似乎比較簡單,但是內涵卻極其深刻,抽象、封裝、繼承、委托、多態等面向對象設計中的理論都得到了很好的體現,應用范圍非常廣泛。

參考

《Head First 設計模式》

《精通 python 設計模式》

《Python 編程實戰》

最后,感謝女朋友支持。

歡迎關注(April_Louisa)

請我喝芬達

歡迎關注

請我喝芬達

總結

以上是生活随笔為你收集整理的python工厂模式 django_python设计模式-工厂方法模式的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。