標簽: python 設(shè)計模式 工廠模式
引子
如何將實例化具體類的代碼從應用中抽離,或者封裝起來,使它們不會干擾應用的其他部分?
就拿書里Pizza店的例子吧,雖然我不喜歡披薩餅
開始......
首先不知道什么原因開了一間披薩店(PizzaStore),然后我可以在里面訂購披薩(orderPizza)
#開了家店
class PizzaStore(object):
#可以定披薩
def orderPizza(self):
self.pizza = Pizza()
print(self.pizza.prepare())
print(self.pizza.bake())
print(self.pizza.cut())
print(self.pizza.box())
不過現(xiàn)在只有一種披薩可以定,完整的代碼如下
#目前只有一種披薩可以定
class Pizza(object):
def prepare(self):
return "prepare pizza"
def bake(self):
return "bake pizza"
def cut(self):
return "cut pizza"
def box(self):
return "box pizza"
class PizzaStore(object):
def orderPizza(self):
self.pizza = Pizza()
print(self.pizza.prepare())
print(self.pizza.bake())
print(self.pizza.cut())
print(self.pizza.box())
緊接著
一種披薩吃兩天我就膩了,這家店剛好又出來幾種披薩,他們分別是cheese,greek,pepperoni口味的
class CheesePizza(object): #第一種pizza
def prepare(self):
return "prepare Cheese pizza"
def bake(self):
return "bake Cheese pizza"
def cut(self):
return "cut Cheese pizza"
def box(self):
return "box Cheese pizza"
class GreekPizza(object): #第二種pizza
def prepare(self):
return "prepare Greek pizza"
def bake(self):
return "bake Greek pizza"
def cut(self):
return "cut Greek pizza"
def box(self):
return "box Greek pizza"
class PepperoniPizza(object): #第三種pizza
def prepare(self):
return "prepare Pepperoni pizza"
def bake(self):
return "bake Pepperoni pizza"
def cut(self):
return "cut Pepperoni pizza"
def box(self):
return "box Pepperoni pizza"
現(xiàn)在再需要定披薩,我就需要說清楚我要來哪種了,這樣披薩店就需要在需要給個菜單出來讓我能選擇我需要的披薩
class PizzaStore(object):
def __init__(self, type):
self.type = type
#==========選擇披薩的類型Begin============#
def orderPizza(self):
if self.type == "CHEESE":
self.pizza = CheesePizza()
if self.type == "GREEK":
self.pizza = GreekPizza()
if self.type == "PEPPERONI":
self.pizza = PepperoniPizza()
#==========選擇披薩的類型End============#
print(self.pizza.prepare())
print(self.pizza.bake())
print(self.pizza.cut())
print(self.pizza.box())
似乎這樣就應該可以了,但是這三種披薩可能遠遠不能滿足作為一個披薩店主的你,我想要隨時增加一些流行的口味,例如clam,veggie.......
class PizzaStore(object):
def __init__(self, type):
self.type = type
#==========選擇披薩的類型Begin==========#
def orderPizza(self):
if self.type == "CHEESE":
self.pizza = CheesePizza()
if self.type == "GREEK":
self.pizza = GreekPizza()
if self.type == "PEPPERONI":
self.pizza = PepperoniPizza()
#==========新增加的披薩類型Begin========#
if self.type == "CLAM":
self.pizza = ClamPizza()
if self.type == "VEGGIE":
self.pizza = VeggiePizza()
#==========選擇披薩的類型End============#
print(self.pizza.prepare())
print(self.pizza.bake())
print(self.pizza.cut())
print(self.pizza.box())
好像違反了一個設(shè)計原則,要對修改關(guān)閉,如果需要增減披薩的類型,我就必須到orderPizza方法中不停的增減。
移出變化的部分
將不斷變化的部分移到另一個對象中,由他專職創(chuàng)建披薩,這個專職創(chuàng)建披薩的地就是工廠。"一旦有了SimplePizzaFactory,orderPizza()就變成此對象的客戶。當需要披薩時就叫披薩工廠去做一個。"
先來創(chuàng)建一個披薩工廠
class SimplePizzaFactory(object):
# 定義一個createPizza方法,所有客戶都使用這個方法來實例化新對象
def createPizza(self, type):
#===========這些跟之前的沒有區(qū)別=============#
self.type = type
if self.type == "CHEESE":
self.pizza = CheesePizza()
if self.type == "GREEK":
self.pizza = GreekPizza()
if self.type == "PEPPERONI":
self.pizza = PepperoniPizza()
#返回一個pizza實例
return self.pizza
工廠有了,還需要披薩店鋪,這個店鋪和之前唯一的不同就是它不再自己直接生產(chǎn)披薩,而是委托給了工廠去she生產(chǎn)
class PizzaStore(object):
def __init__(self):
#將工廠傳進來,委托工廠生產(chǎn)披薩實例
self.factory = SimplePizzaFactory()
#還是一樣的orderPizza方法,只不過這次它不再自己生產(chǎn)了,而是通過工廠的createPizza方法,
#傳入需要的披薩種類,由工廠直接生產(chǎn)了
def orderPizza(self, type):
#通過工廠的createPizza方法,返回需要的披薩實例
self.pizza = self.factory.createPizza(type)
print(self.pizza.prepare())
print(self.pizza.bake())
print(self.pizza.cut())
print(self.pizza.box())
這樣看來,好像只是把生產(chǎn)環(huán)節(jié)重新創(chuàng)建了一個類,這確實比較像是一種編程習慣,但是確實被稱作工廠模式,簡單工廠模式
類圖如下:
![2016-02-25_213919.png-30.6kB][1]
更多的披薩
加盟店來了,一共來了兩家,NewYork和Chicago,他們也生產(chǎn)類圖中四種類型的披薩,但是每家店生產(chǎn)的口味是自己家獨特的,例如都是cheese披薩,NewYork生產(chǎn)NewYork口味的cheese披薩,Chicago生產(chǎn)Chicago口味的cheese披薩,雖然不知道有什么不同,但現(xiàn)實中他們確實可能這么做。
那我在定披薩的時候應該按照怎樣的流程去得到我想要的披薩呢?
![2016-02-25_224609.png-9.5kB][2]
按照這種流程,類圖如下
![2016-02-25_230157.png-39.2kB][3]
首先創(chuàng)建一個PizzaStore的抽象類,這里面有一個createPizza的抽象方法
class PizzaStore(object):
def createPizza(self, type):
pass
def orderPizza(self, type):
#這里有一個實例的createPizza方法,記住這里
self.pizza = self.createPizza(type)
self.pizza.prepare()
self.pizza.bake()
self.pizza.cut()
self.pizza.box()
return self.pizza
創(chuàng)建一個具體的店鋪
class NYPizzaStore(PizzaStore):
#這里具體化了其父類里面的createPizza方法,返回其特有口味的披薩實例,其父類
#里面orderPizza方法最終就是通過調(diào)用子類的createPizza方法實現(xiàn)實例化,也就是
#通過子類進行實例化
def createPizza(self, item):
self.item = item
if self.item == "CHEESE":
return NYStyleCheesePizza()
if self.item == "CLAM":
return NYStyleClamPizza()
你可以創(chuàng)建很多的加盟店,都有自己不同的生產(chǎn)披薩的方式
下面來創(chuàng)建披薩
#先定義一個基類,所有特定口味的披薩類型繼承自這個基類,通過方法的覆蓋實現(xiàn)特定的披薩
class Pizza(object):
def __init__(self, name):
self.name = name
def prepare(self):
print("Prepare " + self.name)
def bake(self):
print("Bake for 25 min at 350")
def cut(self):
print("Cutting the pizza into diagonal slices")
def box(self):
print("Place pizza in official PizzaStore box")
def getName(self):
return (self.name)
#======創(chuàng)建兩種特定口味的披薩begin======#
class NYStyleCheesePizza(Pizza):
def __init__(self):
super(NYStyleCheesePizza, self).__init__("NY Style Sauce and Cheese Pizza")
class NYStyleClamPizza(Pizza):
def __init__(self):
super(NYStyleClamPizza, self).__init__("NY Style Sauce and Clam Pizza")
#======創(chuàng)建兩種特定口味的披薩end ======#
實現(xiàn)
按照上面的流程圖
#選擇一個披薩店鋪
nyPizzaStore = NYPizzaStore()
#下一個特定口味的訂單
pizza = nyPizzaStore.orderPizza("CHEESE")
#orderPizza調(diào)用子類的createPizza方法,生產(chǎn)特定口味的披薩,這里是NYStyleCheesePizza
print(pizza.getName())
#orderPizza調(diào)用子類的createPizza方法,生產(chǎn)特定口味的披薩,這里是NYStyleClamPizza
pizza = nyPizzaStore.orderPizza("CLAM")
print(pizza.getName())
返回的結(jié)果如下
#=========NewYorkCheesePizza============#
Prepare NY Style Sauce and Cheese Pizza
Bake for 25 min at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
NY Style Sauce and Cheese Pizza
#=========NewYorkClamPizza============#
Prepare NY Style Sauce and Clam Pizza
Bake for 25 min at 350
Cutting the pizza into diagonal slices
Place pizza in official PizzaStore box
NY Style Sauce and Clam Pizza
最后來看看工廠方法的定義吧
定義了一個創(chuàng)建對象的接口,但由子類決定要實例化的類是哪一個,工廠方法讓類的實例化推遲到子類
正如上面類圖里顯示的一樣,抽象的PizzaStore提供了一個創(chuàng)建對象的方法createPizza,也叫作工廠方法。子類真正實現(xiàn)這個createPizza方法創(chuàng)建出具體產(chǎn)品。
創(chuàng)建者類不需要直到實際創(chuàng)建的產(chǎn)品是哪一個,選擇了使用了哪個子類,自然也就決定了實際創(chuàng)建的產(chǎn)品是什么。
[1]: http://static.zybuluo.com/plectrum/yy3t687aps6we5gn8lxvhkbg/2016-02-25_213919.png
[2]: http://static.zybuluo.com/plectrum/0bd0zjujyxpwq7n7dlu6ww0z/2016-02-25_224609.png
[3]: http://static.zybuluo.com/plectrum/0kteubh1u0nydonsjkoltxwu/2016-02-25_230157.png