一.理解工廠模式
在面向對象編程中,術語“工廠”表示一個負責創建替他類型對象的類。通常情況下,作為一個工廠的類有一個對象以及與它關聯的多個方法。客戶端使用某些參數調用此方法,之后,工廠會據此創建所需類型的對象,然后將它們返回給客戶端。
簡單理解:工廠模式依然是一種創建型設計模式,作為工廠,它所關心的是產品的產生,也就是對象的創建,我們利用工廠來創建對象,而不必我們親自創建對象,我們無需去理解如何創建對象,只需要向工廠提出要求,讓工廠去根據你的要求,給你生產你要的產品,給你相應的對象,這種模式便叫做工廠模式。
二.工廠模式的優點
-
松耦合,對象的創建獨立於類的實現
-
客戶端無需了解創建對象的類,只需知道需要傳遞的接口,方法和參數就能夠創建所需要的對象
-
很容易擴展工廠添加其他類型對象的創建,而使用者只需要改變參數就可以了
三.python實現工廠模式
1.簡單工廠模式
from abc import ABCMeta,abstractmethod
class Coke(metaclass=ABCMeta):
@abstractmethod
def drink(self):
pass
class Coca(Coke):
def drink(self):
print('drink Coca-Cola')
class Pepsi(Coke):
def drink(self):
print('drink Pepsi-Cola')
class Fast_food_restaurant():
def make_coke(self ,name):
return eval(name)()
KCD=Fast_food_restaurant()
coke=KCD.make_coke('Coca')
coke.drink()#drink Coca-Cola
ABCMeta是python的一個元類,用於在Python程序中創建抽象基類,抽象基類中聲明的抽象方法,使用abstractmethod裝飾器裝飾。
eval(類名)返回的是一個class類型的對象
我們建立一個可樂的抽象類,百事可樂和可口可樂繼承這個抽象類,我們又建立了快餐店類,也就是所說的工廠類,讓它生產可樂。當用戶需要可樂時,只需要告訴快餐店做一份什么品牌的可樂,告訴快餐店可樂的名字,然后快餐店使用make_coke方法做可樂,返回了你所需要的對象——一杯可口可樂,然后就可以快樂的喝可樂了。。
2.工廠方法模式
簡單工廠模式已經幫我們做到我們需要某種對象時,可以不關心對象是怎么創建的,只需要向工廠類要對象即可,但是如果我們又多了一種對象,例如又出現了一個可樂品牌,嗯,我們叫它sfencs可樂吧,那么我們快餐店也得新添加這種可樂,也就是工廠類也得能夠創建sfencs可樂對象了,但是這樣就得在工廠類中加入新的邏輯判斷來根據用戶需求制造新添加的這個對象,顯然是不恰當的,因為這樣每當有一個新的類型的可樂增加的時候,我們都得修改工廠類的邏輯代碼,使之能夠判斷出新的類型。這個問題使用工廠方法模式可以得到解決。
這里有一個小問題,如上面的簡單工廠模式的代碼,如果要新加sfencs可樂,似乎並不需要修改快餐店工廠類,只需要在sfencs可樂類定義之后,依然向make_coke函數傳遞類名即可,那這樣豈不是不需要工廠方法模式了嗎?
對於這個現象,其實是得益於eval()函數的功能,它能依據傳入的字符串轉換成相應的類,也就是eval函數就是工廠類的邏輯判斷,如果不使用eval,那么邏輯判斷可能就是多個if語句了,判斷條件就是輸入的字符串參數是否等於這個,是否等於那個。。。等。但是eval使用也有很大的局限性,它只能根據字符串來判斷,我們不一定創建對象時都知道它的類名。除此之外,個人感覺eval這個函數有點厲害,越厲害就有可能造成不必要的麻煩,eval使用時還是得多注意。
接下來介紹工廠方法模式:
from abc import ABCMeta,abstractmethod
class Coke(metaclass=ABCMeta):
@abstractmethod
def drink(self):
pass
class Coca(Coke):
def drink(self):
print('drink Coca-Cola')
class Pepsi(Coke):
def drink(self):
print('drink Pepsi-Cola')
class Sfencs(Coke):
def drink(self):
print('drink Sfencs-Cola')
class Fast_food_restaurant(metaclass=ABCMeta):
@abstractmethod
def make_coke(self):
pass
class Coca_produce(Fast_food_restaurant):
def make_coke(self):
return Coca()
class Pepsi_produce(Fast_food_restaurant):
def make_coke(self):
return Pepsi()
class Sfencs_produce(Fast_food_restaurant):
def make_coke(self):
return Sfencs()
KCD=Sfencs_produce()
coke=KCD.make_coke()
coke.drink()#drink Sfencs-Cola
工廠方法模式將原來的工廠類變為了抽象類,不同類型的可樂通過不同的子類生產,也就是工廠方法模式定義了一個創建對象的接口,但具體創建哪個類的對象由子類來決定,這種方式的邏輯判斷相當於交給了客戶端,也就是KCD=Sfencs_produce()來選擇使用哪個子類,這樣如果有新可樂產品出現的話,只需要再寫一個子類繼承工廠抽象類。
這里的類中,快餐店抽象類也叫做抽象工廠類,它的子類稱為具體工廠類。可樂也一樣,Coke為抽象產品類,它的子類為具體產品類。
3.抽象工廠模式
抽象工廠模式的主要目的是提供一個接口來創建一系列相關對象而無需指定具體的類。這個模式與與工廠方法模式的區別在於,它的一個方法子類,可以創建一系列的對象。
依然用可樂來舉例,只喝普通的可樂還不足以讓我們非常快樂,那么如果有一杯冰可樂,想必就能滿足我們了。
於是我們的抽象產品類變為了兩個,一個是冰可樂,一個是普通可樂,具體產品類有百事冰可樂、可口可樂冰可樂,普通百事,普通可口可樂。抽象工廠類有生產冰可樂和生產普通可樂的抽象方法,具體工廠類有百事工廠,可口可樂工廠。
from abc import ABCMeta,abstractmethod
class Ice_coke(metaclass=ABCMeta):
@abstractmethod
def drink(self):
pass
class Ordinary_coke(metaclass=ABCMeta):
@abstractmethod
def drink(self):
pass
class Coca_ice(Ice_coke):
def drink(self):
print('drink Coca-ice-Cola')
class Pepsi_ice(Ice_coke):
def drink(self):
print('drink Pepsi-ice-Cola')
class Coca_ordinary(Ordinary_coke):
def drink(self):
print('drink Coca-ordinary-Cola')
class Pepsi_ordinary(Ordinary_coke):
def drink(self):
print('drink Pepsi-ordinary-Cola')
class Fast_food_restaurant(metaclass=ABCMeta):
@abstractmethod
def make_ice_coke(self):
pass
@abstractmethod
def make_ordinary_coke(self):
pass
class Coca_produce(Fast_food_restaurant):
def make_ice_coke(self):
return Coca_ice()
def make_ordinary_coke(self):
return Coca_ordinary()
class Pepsi_produce(Fast_food_restaurant):
def make_ice_coke(self):
return Pepsi_ice()
def make_ordinary_coke(self):
return Pepsi_ordinary()
KCD=Coca_produce()
coke=KCD.make_ice_coke()
coke.drink()#drink Coca-ice-Cola
這樣再有其他類型的可樂或者其他品牌的可樂,只需要添加方法或者類就可以了。
參考《Python設計模式(第2版)》