详解设计模式中的工厂方法模式在Python程序中的运用

工厂方法(Factory Method)模式又称为虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,属于类的创建型模式。在工厂方法模式中,父类负责定义创建对象的公共接口,而子类则负责生成具体的对象,这样做的目的是将类的实例化操作延迟到子类中完成,即由子类来决定究竟应该实体化哪一个类。
在简单工厂模式中,一个工厂类处于对产品类进行实例化的中心位置上,它知道每一个产品类的细节,并决定何时哪一个产品类应当被实例化。简单工厂模式的优点是能够使客户端独立于产品的创建过程,并且在系统中引入新产品时无需对客户端进行修改,缺点是当有新产品要加入到系统中时,必须对工厂类进行修改,以加入必要的处理逻辑。简单工厂模式的致命弱点就是处于核心地位的工厂类,因为一旦它无法确定要对哪个类进行实例化时,就无法使用该模式,而工厂方法模式则可以很好地避免这一问题。
考虑这样一个应用程序框架(Framework),它可以用来浏览各种格式的文档,如TXT、DOC、PDF、HTML等,设计时为了让软件的体系结构能够尽可能地通用,定义了Application和Document这两个抽象父类,客户必须通过它们的子类来处理某一具体类型的文档。例如,要想利用该框架来编写一个PDF文件浏览器,必须先定义PDFApplication和PDFDocument这两个类,它们应该分别继承于Application和Document。
Application的职责是对Document进行管理,并且在需要时创建它们,比如当用户从菜单中选择Open或者New的时候,Application就要负责创建一个Document的实例。显而易见,被实例化的特定Document子类是与具体应用相关的,因此Application无法预测哪个Document的子类将被实例化,它只知道一个新的Document何时(When)被创建,但并不知道哪种(Which)具体的Document将被创建。此时若仍坚持使用简单工厂模式会出现一个非常尴尬的局面:框架必须实例化类,但它只知道不能被实例化的抽象类。
解决的办法是使用工厂方法模式,它封装了哪一个Document子类将被创建的信息,并且能够将这些信息从框架中分离出来。如图1所示,Application的子类重新定义了Application的抽象方法createDocument(),并返回某个恰当的Document子类的实例。我们称createDocument()是一个工厂方法(factory method),因为它非常形象地描述了类的实例化过程,即负责"生产"一个对象。

简单说来,工厂方法模式的作用就是可以根据不同的条件生成各种类的实例,这些实例通常属于多个相似的类型,并且具有共同的父类。工厂方法模式将这些实例的创建过程封装了起来,从而简化了客户程序的编写,并改善了软件体系结构的可扩展性,使得将来能够以最小的代价加入新的子类。工厂方法这一模式适合在如下场合中运用:
当无法得知必须创建的对象属于哪个类的时候,或者无法得知属于哪个类的对象将被返回的时候,但前提是这些对象都符合一定的接口标准。
当一个类希望由它的子类来决定所创建的对象的时候,其目的是使程序的可扩展性更好,在加入其他类时更具弹性。
当创建对象的职责被委托给多个帮助子类(helper subclass)中的某一个,并且希望将哪个子类是代理者这一信息局部化的时候。
需要说明的是,使用工厂方法模式创建对象并不意味着一定会让代码变得更短(实事上往往更长),并且可能需要设计更多的辅助类,但它的确可以灵活地、有弹性地创建尚未确定的对象,从而简化了客户端应用程序的逻辑结构,并提高了代码的可读性和可重用性。

拿一个动物工厂来举例说明

class Animal(object):
  def eat(self, food):
    raise NotImplementedError()

class Dog(Animal):
  def eat(self, food):
    print '狗吃', food

class Cat(Animal):
  def eat(self, food):
    print '猫吃', food

class AnimalFactory(object):
  def create_animal(self):
    raise NotImplementedError()

class DogFactory(Animal):
  def create_animal(self):
    return Dog()

class CatFactory(AnimalFactory):
  def create_animal(self):
    return Cat()

def client():
  animal_factory = DogFactory()
  animal = animal_factory.create_animal()
  animal.eat('肉骨头')

  animal_factory = CatFactory()
  animal = animal_factory.create_animal()
  animal.eat('鱼骨头')

下面是简单工厂模式的实现:

class Animal(object):
  def eat(self, food):
    raise NotImplementedError()

class Dog(Animal):
  def eat(self, food):
    print '狗吃', food

class Cat(Animal):
  def eat(self, food):
    print '猫吃', food

def create_animal(name):
  if name == 'dog':
    return Dog()
  elif name == 'cat':
    return Cat()

def client():
  animal = create_animal('dog')
  animal.eat('肉骨头')
  animal = create_animal('cat')
  animal.eat('鱼骨头')

看起来工厂方法模式要复杂很多啊,也没觉得比简单工厂模式有什么好处,为什么还要用工厂方法模式呢? 简单工厂模式的优点很明显,工厂函数封装了逻辑判断,客户端使用负担要小很多。相应的问题也很明显,要增加新的产品类型,就需要修改工厂函数,这违背了开闭原则。 但是工厂方法模式似乎绕了一圈又回到原始时代了,下面写不就行了吗,何必外面套一层Factory:

class Animal(object):
  def eat(self, food):
    raise NotImplementedError()

class Dog(Animal):
  def eat(self, food):
    print '狗吃', food

class Cat(Animal):
  def eat(self, food):
    print '猫吃', food
def client():
  dog = Dog()
  dog.eat('肉骨头')

  cat = Cat()
  cat.eat('鱼骨头')

工厂方法模式,对于需要做强类型检查的语言比如Java、C++等在组织代码时是有好处的。对于Python这种动态语言来说,感觉体现不出太多价值,或许我还没有理解工厂方法模式的真谛。

(0)

相关推荐

  • 使用Mixin设计模式进行Python编程的方法讲解

    Mixin模式是一种在python里经常使用的模式,适当合理的应用能够达到复用代码,合理组织代码结构的目的. Python的Mixin模式可以通过多继承的方式来实现, 举例来说,我们自定义一个简单的具有嵌套结构的数据容器: class SimpleItemContainer(object): def __init__(self, id, item_containers): self.id = id self.data = {} for item in item_containers: self.

  • Python的设计模式编程入门指南

    有没有想过设计模式到底是什么?通过本文可以看到设计模式为什么这么重要,通过几个Python的示例展示为什么需要设计模式,以及如何使用. 设计模式是什么? 设计模式是经过总结.优化的,对我们经常会碰到的一些编程问题的可重用解决方案.一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码.反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板.设计模式不会绑定具体的编程语言.一个好的设计模式应该能够用大部分编程语言实现(如果做不到全部的话,具体取决于语言特性).最为重要的是,设计模

  • 举例分析Python中设计模式之外观模式的运用

    应用特性: 在很多复杂而小功能需要调用需求时,而且这些调用往往还有一定相关性,即一调用就是一系列的. 结构特性: 把原本复杂而繁多的调用,规划统一到一个入口类中,从此只通过这一个入口调用就可以了. 代码结构示例: class ModuleOne(object): def Create(self): print 'create module one instance' def Delete(self): print 'delete module one instance' class Module

  • Python设计模式之观察者模式实例

    关于设计模式中的观察者模式,定义如下(维基百科): 觀察者模式(有時又被稱為發布/訂閱模式)是軟體設計模式的一種.在此種模式中,一個目標物件管理所有相依於它的觀察者物件,並且在它本身的狀態改變時主動發出通知.這通常透過呼叫各觀察者所提供的方法來實現.此種模式通常被用來實作事件處理系統.简单来说,一个被观察者有很多观察者,被观察者的状态的改变会引起所有观察者的响应操作. 那么我们用Python2.7来实现观察者模式. Python中的集合set 集合(set),类似于列表(list),但是它没有重

  • 实例解析Python设计模式编程之桥接模式的运用

    我们先来看一个例子: #encoding=utf-8 # #by panda #桥接模式 def printInfo(info): print unicode(info, 'utf-8').encode('gbk') #抽象类:手机品牌 class HandsetBrand(): soft = None def SetHandsetSoft(self, soft): self.soft = soft def Run(self): pass #具体抽象类:手机品牌1 class HandsetBr

  • Python设计模式之单例模式实例

    注:使用的是Python 2.7. 一个简单实现 复制代码 代码如下: class Foo(object):    __instance = None    def __init__(self):        pass    @classmethod    def getinstance(cls):        if(cls.__instance == None):            cls.__instance = Foo()        return cls.__instance

  • 举例讲解Python设计模式编程中的访问者与观察者模式

    访问者模式 我觉得Visitor模式是在补修改已有程序结构前提下,通过添加额外的访问者完成对代码功能的拓展 为什么这样用?当你的类层次较多,在某层结构中增加新的方法,要是在基类上面添加或者变更,可能破坏原来的设计, 有兼容问题,所以只在需要的类上面动态添加. python的例子 这里是个构建车的例子,每个部件都有一个accept的方法接受我上面说的所谓'访问者',而这个访问者 以参数的方式传进来,但是其实他是一个含有一些功能的类的实例,它拥有很多个visit开头的方法对应不同的部件. 这样就不需

  • Python设计模式之代理模式实例

    翻墙常用的方式就是使用代理(Proxy),其基本过程如下: 浏览器<-->代理服务器<-->服务器 如果浏览器请求不到服务器,或者服务器无法响应浏览器,我们可以设定将浏览器的请求传递给代理服务器,代理服务器将请求转发给服务器.然后,代理服务器将服务器的响应内容传递给浏览器.当然,代理服务器在得到请求或者响应内容的时候,本身也可以做些处理,例如缓存静态内容以加速,或者说提取请求内容或者响应内容做些正当或者不正当的分析.这种翻墙方式,就是设计模式中代理模式(Proxy Pattern)

  • Python设计模式中单例模式的实现及在Tornado中的应用

    单例模式的实现方式 将类实例绑定到类变量上 class Singleton(object): _instance = None def __new__(cls, *args): if not isinstance(cls._instance, cls): cls._instance = super(Singleton, cls).__new__(cls, *args) return cls._instance 但是子类在继承后可以重写__new__以失去单例特性 class D(Singleto

  • 举例讲解Python设计模式编程的代理模式与抽象工厂模式

    代理模式 Proxy模式是一种常用的设计模式,它主要用来通过一个对象(比如B)给一个对象(比如A) 提供'代理'的方式方式访问.比如一个对象不方便直接引用,代理就在这个对象和访问者之间做了中介 你先设想:一个对象提供rgb三种颜色值,我想获得一个对象的rgb三种颜色,但是我不想让你获得蓝色属性,怎么办? class Proxy(object): def __init__(self, subject): self.__subject = subject # 代理其实本质上就是属性的委托 def _

  • 设计模式中的原型模式在Python程序中的应用示例

    原型模式: 原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 原型模式本质就是克隆对象,所以在对象初始化操作比较复杂的情况下,很实用,能大大降低耗时,提高性能,因为"不用重新初始化对象,而是动态地获得对象运行时的状态". 应用特性: 需要大量的基于某个基础原型进行微量修改而得到新原型时使用. 结构特性: 对象的复制机制,即浅复制和深复制. 例1: #!/usr/bin/env python #encoding: utf-8 from copy import copy, d

随机推荐