Python工厂模式

标签: 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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • 工厂模式包含三种模式:简单工厂模式、工厂方法模式和抽象工厂模式。 简单工厂模式 定义简单工厂模式:由一个工厂类根据...
    RickGe阅读 344评论 0 0
  • 工厂模式,一个工厂实例化一个指定类。
    虾想家阅读 272评论 0 0
  • 客户需求 程序设计 1、PizzaStore是用来给客户下订单买pizza的,所以每个PizzaStore都会有一...
    BlainPeng阅读 546评论 0 2
  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,875评论 1 15
  • 21: Mit Erfolg和2020,开始看2020lese 22: 2020阅读部分+语法passiv
    WB16阅读 125评论 0 0