编程学习网 > 编程语言 > Python > 新手非常费解的python工厂模式代码介绍
2021
08-04

新手非常费解的python工厂模式代码介绍

工厂模式是一个令初学者非常费解的模式。因为介绍工厂模式的时候会连续介绍1个编程习惯和2个设计模式,分别是「简单工厂」设计习惯、「工厂方法模式」和「抽象工厂模式」,难以一次理清楚几个重要知识点的逻辑。不过据网上各种大佬所说,平时写代码的时候一般都只会使用简单工厂,而工厂方法模式和抽象工厂模式一般只有大项目才会用,很多人甚至一辈子都用不上。比如,PyTorch Geometric开源工具包的大佬作者Matthias Fey最近提出的 GNNAutoScale 的开源代码也只是用简单工厂来写代码。可见工厂方法模式和抽象工厂模式只是大工程中的“屠龙术”,平时写代码估计很难遇上了,学了也难以和实践结合。本文只是对工厂模式粗浅介绍,如有不对的地方请大家指出。


本文分为以下几个部分:


  • 为什么new需要封装?
  • 简单工厂
  • 工厂方法模式
  • 抽象工厂模式
  • 总结


为什么new需要封装?

new是java中的一个语法,作用是声明并初始化一个变量或对象,就想C中的int、float一样。在python中,我们虽然不用new来实现它,但也总是会隐式地声明和初始化变量或对象。大学刚接触编程那会儿,几乎所有C的代码一上来就会“int x = 0;”这样声明初始化变量,根本没听说过变量或对象初始化还要封装的。但是工厂模式就是将这些初始化变量的代码封装成一个工厂,和其他部分「解耦」。

然而实际项目和考试不一样,实际项目是需要合作写代码的,需要接着别人的代码进行开发的。我们要做的常常是「调用别人的代码」,而「不要自己去new别人负责的模块」。因为这时候别人哪怕是把他的模块改个名字,都会导致你的模块出问题,需要迫使你修改自己负责那部分。自己这块代码会被别人负责的模块牵着走。

工厂模式就是将这种关系「解耦」,让自己负责的代码部分「经得起推敲」。什么叫“经得起推敲”?「少修改叫做“经得起推敲”」。很多时候仅仅是需求发生改变就需要修改自己的这部分代码,那自己写的那部分代码就不算是经得起推敲的。


简单工厂

假如我们要实现一个制作PizzaStore的类的orderPizza函数。函数一开始会传入一个str表示顾客要哪种pizza,而你需要负责整个流程,保证pizza按照prepare、bake、cut、box四道工序做出来。以下是代码示例:

class PizzaStore():
    def orderPizza(self,name):
        if name in ['cheese']:
            pizza = CheesePizza()
        elif name in ['greek']:
            pizza = GreekPizza()
        elif name in ['pepperoni']:
            pizza = PepperoniPizza()

        pizza.prepare()
        pizza.bake()
        pizza.cut()
        pizza.box()
        return pizza

注意到在这段代码中,每个pizza类(CheesePizza、GreekPizza、PepperoniPizza)和里面的方法(prepare、bake、cut、box)都不是自己实现的,我们只是想调用别人已经实现好的。

对于方法(prepare、bake、cut、box),我们的调用不会有问题。因为在框架设计时,这些接口就约定好了,不能随意修改。然而对于pizza类(CheesePizza、GreekPizza、PepperoniPizza),「一但有新pizza类型出现或者原本的pizza被删除,那就要修改orderPizza函数」。


熟悉简单工厂的人会写出下面的代码:

def create_pizza(name):
    if name in ['cheese']:
        pizza = CheesePizza()
    elif name in ['greek']:
        pizza = GreekPizza()
    elif name in ['pepperoni']:
        pizza = PepperoniPizza()
    return pizza

class PizzaStore():
    def orderPizza(self,name):
        pizza = create_pizza(name)

        pizza.prepare()
        pizza.bake()
        pizza.cut()
        pizza.box()
        return pizza

看起来和之前一个没有本质区别,仅仅是「把pizza初始化的过程封装了起来」。其实这是一个很重要的变化,那就是我们可以说PizzaStore函数「经得起推敲」了,因为在一些新的pizza需求来临时,我们「不需要修改PizzaStore函数」,只需要修改create_pizza。而create_pizza可以再交给负责pizza类各种实现的人来负责。


工厂方法模式

相比于简单工厂,工厂方法模式通过「让子类决定该创建的对象」是什么,来达到将对象创建的过程封装的目的。其代码实现如下

class PizzaStore():
    def orderPizza(self,name):
        pizza = self.create_pizza(name)

        pizza.prepare()
        pizza.bake()
        pizza.cut()
        pizza.box()
        return pizza

    def create_pizza(self,name):
        raise NotImplementedError

这次连create_pizza都不写了,而是把它「交给了别人」——继承PizzaStore类的人。这样我们的PizzaStore类就是更加经得起推敲了。


抽象工厂模式

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。抽象工厂模式和工厂方法模式一样,都让子类决定该创建的对象是什么。不同之处在于,工厂方法模式设计中的子类只能创建一个产品,而「抽象工厂模式中的子类能创建多个同类型产品」。多个同类型产品是通过策略模式提到的「组合」实现的。


实际上,抽象工厂模式在指导如何「设计子类」,也就是PizzaStore的子类,让**每个子类能创建多个产品****。其代码如下

class NYPizzaStore(PizzaStore):
    def __init__(self, ingredientFactory):
        self.ingredientFactory = ingredientFactory

    def create_pizza(self,name):
      if name in ['cheese']:
          pizza = NYCheesePizza(self.ingredientFactory)
      elif name in ['greek']:
          pizza = NYGreekPizza(self.ingredientFactory)
      elif name in ['pepperoni']:
          pizza = NYPepperoniPizza(self.ingredientFactory)
      return pizza

注意其中的ingredientFactory也是个工厂。NYPizzaStore将ingredientFactory作为初始化pizza对象时候的输入,这样就能得到基于「多种原材料」生产的pizza了。


总结

工厂模式遵循「开放-封闭原则」,将已经验证无误的代码封装好,与(经常需要修改的)创建的对象的部分「解耦」。三种工厂的区别如下

简单工厂:「唯一工厂类,一个产品抽象类」,工厂类的创建方法依据入参判断并创建具体产品对象。

工厂方法模式:继承得到「多个工厂类,一个产品抽象类」,利用多态创建不同的产品对象,避免了大量的if-else判断。

抽象工厂模式:继承得到「多个工厂类,组合得到多个产品抽象类」,产品子类分组,同一个工厂实现类创建同组中的不同产品,减少了工厂子类的数量。

以上就是“新手非常费解的python工厂模式代码介绍”的详细内容,想要获取更多Python教程欢迎关注编程学习网

扫码二维码 获取免费视频学习资料

Python编程学习

查 看2022高级编程视频教程免费获取