资讯专栏INFORMATION COLUMN

python设计模式-抽象工厂模式

seal_de / 1763人阅读

摘要:源码参考抽象工厂模式抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体类。工厂方法模式和抽象工厂模式如何选择开始的时候,可以选择工厂方法模式,因为他很简单只需要继承,并实现工厂方法即可。

问题:在上一篇 python设计模式:工厂方法模式我们尝试使用工厂方法创建了披萨店,现在为了保证披萨加盟店也能有良好的声誉,我们需要统一原材料,这个该如何做呢?

为了确保每家加盟店都是用高质量的原材料,我们打算建造一加原材料工厂,并将原材料运送到各个加盟店。每个加盟店会对原材料有不同的需求,这里我们就可以用上上一篇介绍的工厂方法模式了。

首先,建造原料工厂

然后建造区域的原料工厂(继承自原料工厂)

在区域的原料工厂中实现原料的创建方法。

将原料工厂组合起来,加入到 PizzaStore(上一篇中由工厂方法实现)代码中。

按照这个思路,我们先创建原料工厂

创建原料工厂

创建原料工厂的实现代码如下:

# 原料
class FreshClams:

    def __str__(self):
        return "Fresh Clams"

class MarinaraSauce:

    def __str__(self):
        return "Marinara Sauce"

class ThickCrustDough:

    def __str__(self):
        return "Thick Crust Dough"

class ReggianoCheese:

    def __str__(self):
        return "Reggiano Cheese"

class SlicedPepperoni:

    def __str__(self):
        return "Sliced Pepperoni"

class Garlic:

    def __str__(self):
        return "Garlic"

class Onion:

    def __str__(self):
        return "Onion"

class RedPepper:

    def __str__(self):
        return "Red Pepper"

# 披萨店原料工厂
class PizzaIngredientFactory:

    """
    定义原料工厂
    """

    def create_dough(self):
        raise NotImplementedError()

    def create_sauce(self):
        raise NotImplementedError()

    def create_cheese(self):
        raise NotImplementedError()

    def create_pepperoni(self):
        raise NotImplementedError()

    def create_clam(self):
        raise NotImplementedError()

    def create_veggies(self):
        raise NotImplementedError()

在这个工厂中,每个原料都是一个方法,原料的实现需要在具体的原料工厂中实现。
这里每个原料方法没有做任何工作,只是抛出了NotImplementedError 这样做是为了强制子类重新实现相应的方法,如果不重新实现用到时就会抛出 NotImplementedError。

当然也可以把 PizzaIngredientFactory 的 metaclass 设置成 abc.ABCMeta 这样的话,这个类就是真正的抽象基类。

创建纽约原料工厂
class NYPizzaIngredientFactory(PizzaIngredientFactory):
    def create_dough(self):
        print("Tossing %s" % ThickCrustDough())
        return ThickCrustDough()

    def create_sauce(self):
        print("Adding %s..." % MarinaraSauce())
        return MarinaraSauce()

    def create_cheese(self):
        print("Adding %s..." % ReggianoCheese())
        return ReggianoCheese()

    def create_pepperoni(self):
        print("Adding %s..." % SlicedPepperoni())
        return SlicedPepperoni()

    def create_clam(self):
        print("Adding %s..." % FreshClams())
        return FreshClams()

    def create_veggies(self):
        # 蔬菜可能有多种,这里使用列表
        veggies = [Garlic(), Onion(), RedPepper()]
        for veggie in veggies:
            print("  %s" % veggie)
        return veggies

对于原料家族的每一种原料,我们都提供了原料的纽约版本。

重做 Pizza 类
class Pizza:
    
    name = None
    dough = None
    sauce = None
    cheese = None
    veggies = []
    pepperoni = None
    clam = None

    def prepare(self):
        raise NotImplementedError()

    def bake(self):
        print("Bake for 25 minutes at 350")

    def cut(self):
        print("Cutting the pizza into diagonal slices")

    def box(self):
        print("Place pizza in official PizzaStore box")

    def __str__(self):
        return self.name

上述代码和工厂方法的代码相比,只是把 prepare() 方法抽象出来,需要相应的 具体的 pizza 类来实现 prepare()

实现 芝加哥芝士披萨
class NYStyleCheesePizza(Pizza):

    def prepare(self):
        dough = self.ingredient_factory.create_dough()
        sauce = self.ingredient_factory.create_sauce()
        cheese = self.ingredient_factory.create_cheese()
        clam = self.ingredient_factory.create_clam()
        veggies = self.ingredient_factory.create_veggies()

从上述代码可以发现,Pizza 的原料也是从原料工厂直接获取,现在我们控制了原料。

现在,Pizza 类不需要关心原料,只需要负责制作 pizza 就好。Pizza 和原料被解耦。

重新实现 PizzaStore
class PizzaStore:
    
    # 需要声明原料工厂
    ingredient_factory = None

    def create_pizza(self, pizza_type):
        # 每个需要子类实现的方法都会抛出NotImplementedError
        # 我们也可以把 PizzaStore 的 metaclass 设置成 abc.ABCMeta
        # 这样的话,这个类就是真正的抽象基类
        raise NotImplementedError()

    def order_pizza(self, pizza_type):  # 现在把 pizza 的类型传入 order_pizza()

        pizza = self.create_pizza(pizza_type)

        #  一旦我们有了一个 pizza,需要做一些准备(擀面皮、加佐料),然后烘烤、切片、装盒
        pizza.prepare()
        pizza.bake()
        pizza.cut()
        pizza.box()
        return pizza

class NYStylePizzStore(PizzaStore):
    
    # 将需要用到的原料工厂赋值给变量 ingredient_factory
    ingredient_factory = NYPizzaIngredientFactory()

    def create_pizza(self, pizza_type):
        # 根据 pizza 类型,我们实例化正确的具体类,然后将其赋值给 pizza 实例变量
        if pizza_type == "cheese":
            pizza = NYStyleCheesePizza("NY Style Sauce and Cheese Pizza",
                                       self.ingredient_factory)
        elif pizza_type == "clam":
            pizza = NYStyleClamPizza("NY Style Clam Pizza",
                                     self.ingredient_factory)
        return pizza

通过上述代码可以看到我们做了以下工作:

引入了新类型的工厂(抽象工厂)来创建原料家族

通过抽象工厂提供的接口,我们创建了原料家族。

我们的原料代码从实际的 Pizza 工厂中成功解耦,可以应用到不同地方,响应的,我们可以方便的替换原料工厂来生产不同的 pizza。

来看下下单的代码
def main():
    nystore = NYStylePizzStore()
    pizza = nystore.order_pizza("cheese")
    print("*" * 10)
    print("goodspeed ordered a %s" % pizza)
    print("*" * 10)

和工厂方法的代码相比,没有任何改变。

[源码参考python-design-patter-abstract-factory.py](https://gist.github.com/gusibi/5e0797f5458678322486f999ca87a180)

抽象工厂模式

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体类。

也就是说,抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么,这样依赖,客户就从具体产品中被解耦。

概括来说就是,抽象工厂是逻辑上的一组工厂方法,每个工厂方法各司其职,负责生产不同种类的对象。

我们来看下 抽象工厂模式 的类图:

抽象工厂在 django_factory 中应用比较多,有兴趣的可以看下源码。

抽象工厂模式 和 工厂方法模式 的比较

抽象工厂模式 和 工厂方法模式 都是负责创建对象,但

工厂方法模式使用的是继承

抽象工厂模式使用的是对象的组合

这也就意味着利用工厂方法创建对象需要扩展一个类,并覆盖它的工厂方法(负责将客户从具体类中解耦)。
抽象工厂提供一个用来创建产品家族的抽象类型,这个类型的子类定义了产品被产生的方法。要想使用这个工厂(NYPizzaIngredientFactory),必须先实例化它(ingredient_factory = NYPizzaIngredientFactory()),然后将它传入一些针对抽象类型所写的代码中(也做到了将客户从具体产品中解耦),同时还把一群相关的产品集合起来。

工厂方法模式和抽象工厂模式如何选择

开始的时候,可以选择工厂方法模式,因为他很简单(只需要继承,并实现工厂方法即可)。如果后来发现应用需要用到多个工厂方法,那么是时候使用抽象工厂模式了,它可以把相关的工厂方法组合起来。

抽象工厂模式优点和缺点 优点

可以将客户从具体产品中解耦

抽象工厂可以让对象创建更容易被追踪

同时将对象创建与使用解耦

也可以优化内存占用提升应用性能

缺点

因为抽象工厂是将一组相关的产品集合起来,如果需要扩展这组产品,就需要改变接口,而改变接口则意味着需要改变每个子类的接口

参考链接

python设计模式:工厂方法模式

python-design-patter-abstract-factory.py https://gist.github.com/gusibi/5e0797f5458678322486f999ca87a180


最后,感谢女朋友支持。

欢迎关注(April_Louisa) 请我喝芬达

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/40974.html

相关文章

  • 设计模式抽象工厂模式

    摘要:所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。 0x01.定义与类型 定义:抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口 无需指定它们具体的类 类型:创建型 UML showImg(https://segmentfault.com/img/bVbtBp1?w=800&h=862...

    Acceml 评论0 收藏0
  • Python实现设计模式——工厂模式

    摘要:本文会用实现三种工厂模式的简单例子,所有代码都托管在上。工厂方法模式继承了简单工厂模式的优点又有所改进,其不再通过一个工厂类来负责所有产品的创建,而是将具体创建工作交给相应的子类去做,这使得工厂方法模式可以允许系统能够更高效的扩展。 前言 工厂模式,顾名思义就是我们可以通过一个指定的工厂获得需要的产品,在设计模式中主要用于抽象对象的创建过程,让用户可以指定自己想要的对象而不必关心对象的...

    CrazyCodes 评论0 收藏0
  • python设计模式-工厂方法模式

    摘要:工厂方法模式可以帮助我们将产品的实现从使用中解耦。应用中使用工厂模式的例子的模块使用工厂方法模式来创建表单字段。也使用到了工厂方法模式。中不同数据库连接部分也用到了工厂方法模式。 题目:假设你有一个 pizza 店,功能包括下订单、做 pizza,你的代码会如何写呢? def order_pizza(): pizza = Pizza() pizza.prepare() ...

    pubdreamcc 评论0 收藏0
  • 设计模式工厂方法模式

    摘要:通过工厂方法模式的类图可以看到,工厂方法模式有四个要素工厂接口工厂接口是工厂方法模式的核心,与调用者直接交互用来提供产品。使用场景创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。 0x01.定义与类型 定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化那个类,工厂方法让类的实例化推迟到子类中进行 类型:创建型 uml类图 showImg(https:/...

    geekidentity 评论0 收藏0
  • python之单例模式工厂模式

    摘要:在工厂方法模式中,我们会遇到一个问题,当产品非常多时,继续使用工厂方法模式会产生非常多的工厂类。从简单工厂模式到抽象工厂模式,我们都是在用后一种模式解决前一种模式的缺陷,都是在最大程度降低代码的耦合性。 单例模式 所谓单例模式,也就是说不管什么时候我们要确保只有一个对象实例存在。很多情况下,整个系统中只需要存在一个对象,所有的信息都从这个对象获取,比如系统的配置对象,或者是线程池。这些...

    jayce 评论0 收藏0

发表评论

0条评论

seal_de

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<