标签: python 设计模式 工厂模式
引子
如何将实例化具体类的代码从应用中抽离,或者封装起来,使它们不会干扰应用的其他部分?
就拿书里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())
不过现在只有一种披萨可以定,完整的代码如下
#目前只有一种披萨可以定
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"
现在再需要定披萨,我就需要说清楚我要来哪种了,这样披萨店就需要在需要给个菜单出来让我能选择我需要的披萨
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())
好像违反了一个设计原则,要对修改关闭,如果需要增减披萨的类型,我就必须到orderPizza方法中不停的增减。
移出变化的部分
将不断变化的部分移到另一个对象中,由他专职创建披萨,这个专职创建披萨的地就是工厂。"一旦有了SimplePizzaFactory,orderPizza()就变成此对象的客户。当需要披萨时就叫披萨工厂去做一个。"
先来创建一个披萨工厂
class SimplePizzaFactory(object):
# 定义一个createPizza方法,所有客户都使用这个方法来实例化新对象
def createPizza(self, type):
#===========这些跟之前的没有区别=============#
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
工厂有了,还需要披萨店铺,这个店铺和之前唯一的不同就是它不再自己直接生产披萨,而是委托给了工厂去she生产
class PizzaStore(object):
def __init__(self):
#将工厂传进来,委托工厂生产披萨实例
self.factory = SimplePizzaFactory()
#还是一样的orderPizza方法,只不过这次它不再自己生产了,而是通过工厂的createPizza方法,
#传入需要的披萨种类,由工厂直接生产了
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())
这样看来,好像只是把生产环节重新创建了一个类,这确实比较像是一种编程习惯,但是确实被称作工厂模式
,简单工厂模式
类图如下:
![2016-02-25_213919.png-30.6kB][1]
更多的披萨
加盟店来了,一共来了两家,NewYork和Chicago,他们也生产类图中四种类型的披萨,但是每家店生产的口味是自己家独特的,例如都是cheese披萨,NewYork生产NewYork口味的cheese披萨,Chicago生产Chicago口味的cheese披萨,虽然不知道有什么不同,但现实中他们确实可能这么做。
那我在定披萨的时候应该按照怎样的流程去得到我想要的披萨呢?
![2016-02-25_224609.png-9.5kB][2]
按照这种流程,类图如下
![2016-02-25_230157.png-39.2kB][3]
首先创建一个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
创建一个具体的店铺
class NYPizzaStore(PizzaStore):
#这里具体化了其父类里面的createPizza方法,返回其特有口味的披萨实例,其父类
#里面orderPizza方法最终就是通过调用子类的createPizza方法实现实例化,也就是
#通过子类进行实例化
def createPizza(self, item):
self.item = item
if self.item == "CHEESE":
return NYStyleCheesePizza()
if self.item == "CLAM":
return NYStyleClamPizza()
你可以创建很多的加盟店,都有自己不同的生产披萨的方式
下面来创建披萨
#先定义一个基类,所有特定口味的披萨类型继承自这个基类,通过方法的覆盖实现特定的披萨
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)
#======创建两种特定口味的披萨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")
#======创建两种特定口味的披萨end ======#
实现
按照上面的流程图
#选择一个披萨店铺
nyPizzaStore = NYPizzaStore()
#下一个特定口味的订单
pizza = nyPizzaStore.orderPizza("CHEESE")
#orderPizza调用子类的createPizza方法,生产特定口味的披萨,这里是NYStyleCheesePizza
print(pizza.getName())
#orderPizza调用子类的createPizza方法,生产特定口味的披萨,这里是NYStyleClamPizza
pizza = nyPizzaStore.orderPizza("CLAM")
print(pizza.getName())
返回的结果如下
#=========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
最后来看看工厂方法的定义吧
定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类的实例化推迟到子类
正如上面类图里显示的一样,抽象的PizzaStore提供了一个创建对象的方法createPizza,也叫作工厂方法
。子类真正实现这个createPizza方法创建出具体产品。
创建者类不需要直到实际创建的产品是哪一个,选择了使用了哪个子类,自然也就决定了实际创建的产品是什么。
[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