如何生成Python工厂类

2024-06-21 20:35:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我希望能够基于枚举类创建对象,并使用字典。像这样:

class IngredientType(Enum):
    SPAM        = auto() # Some spam
    BAKE_BEANS  = auto() # Baked beans
    EGG         = auto() # Fried egg

class Ingredient(object):
    pass    
class Spam(Ingredient):
    pass
class BakedBeans(Ingredient):
    pass
class Egg(Ingredient):
    pass


class IngredientFactory(object):
    """Factory makes ingredients"""

    choice = {
        IngredientType.SPAM: IngredientFactory.MakeSpam,
        IngredientType.BAKED_BEANS: IngredientFactory.MakeBakedBeans,
        IngredientType.EGG: IngredientFactory.MakeEgg
    }

    @staticmethod
    def make(type):
        method = choice[type]
        return method()

    @staticmethod
    def makeSpam():
        return Spam()

    @staticmethod
    def makeBakedBeans():
        return BakedBeans()

    @staticmethod
    def makeEgg():
        return Egg()

但我得到了一个错误:

^{pr2}$

由于某些原因,词典无法创建。 我在这里哪里做错了?在


Tags: autoreturnobjecteggdefpassspamclass
3条回答

在看了Bruce Eckel's book之后,我想到了这个:

#Based on Bruce Eckel's book Python 3 example
# A simple static factory method.
from __future__ import generators
import random
from enum import Enum, auto

class ShapeType(Enum):
    CIRCLE  = auto() # Some circles
    SQUARE  = auto() # some squares

class Shape(object):
    pass

class Circle(Shape):
    def draw(self): print("Circle.draw")
    def erase(self): print("Circle.erase")

class Square(Shape):
    def draw(self): print("Square.draw")
    def erase(self): print("Square.erase")

class ShapeFactory(object):

    @staticmethod
    def create(type):
        #return eval(type + "()") # simple alternative
        if type in ShapeFactory.choice:
            return ShapeFactory.choice[type]()

        assert 0, "Bad shape creation: " + type    

    choice = { ShapeType.CIRCLE:  Circle,
               ShapeType.SQUARE:  Square                
             }

# Test factory
# Generate shape name strings:
def shapeNameGen(n):

    types = list(ShapeType)

    for i in range(n):
        yield random.choice(types)

shapes = \
  [ ShapeFactory.create(i) for i in shapeNameGen(7)]

for shape in shapes:
    shape.draw()
    shape.erase()

这将让用户从枚举中选择一个类类型,并阻止任何其他类型。这也意味着用户不太可能写出拼写错误的“坏字符串”。他们只是使用枚举。 然后,测试的输出如下:

^{pr2}$

将映射放在类的末尾,并直接引用方法,因为它们位于同一命名空间中:

choice = {
    IngredientType.SPAM: makeSpam,
    IngredientType.BAKED_BEANS: makeBakedBeans,
    IngredientType.EGG: makeEgg
}

类对象直到类主体中的所有代码都已创建,因此您无法访问类本身。但是,由于类主体是在一个专用的命名空间中处理的,所以您可以访问在该点之前定义的任何属性(这就是为什么映射必须在末尾出现)。还请注意,虽然可以访问全局变量和内置项,但不能访问封闭类或函数的命名空间。在

下面是官方文档中详细但仍然是介绍性的解释,解释了类是如何执行的:https://docs.python.org/3/tutorial/classes.html#a-first-look-at-classes

Python不是Java,也不要求所有的东西都在一个类中。这里您的IngredientFactory类没有状态,只有staticmethods,因此它实际上只是一个单例名称空间,在python中,这是通过使用模块作为单例名称空间和普通函数来完成的。另外,由于Python类已经是可调用的,所以在函数中包装实例化是没有意义的。简单、直接的wrad pythonic实现是:

# ingredients.py

class IngredientType(Enum):
    SPAM        = auto() # Some spam
    BAKE_BEANS  = auto() # Baked beans
    EGG         = auto() # Fried egg

class Ingredient(object):
    pass    

class Spam(Ingredient):
    pass

class Beans(Ingredient):
    pass

class Egg(Ingredient):
    pass


_choice = {
        IngredientType.SPAM: Spam,
        IngredientType.BAKED_BEANS: Beans,
        IngredientType.EGG: Egg
    }

def make(ingredient_type):
    cls = _choice[ingredient_type]
    return cls()

客户代码:

^{pr2}$

FWIWIngredientType枚举在这里没有带来太多东西,甚至使事情变得更加复杂——您可以使用纯字符串:

# ingredients.py

class Ingredient(object):
    pass    

class Spam(Ingredient):
    pass

class Beans(Ingredient):
    pass

class Egg(Ingredient):
    pass


_choice = {
        "spam": Spam,
        "beans": Beans,
        "egg": Egg
    }

def make(ingredient_type):
    cls = _choice[ingredient_type]
    return cls()

客户代码:

import ingredients
egg = ingredients.make("egg")

或者,如果您真的想使用Enum,您至少可以通过使用类本身作为枚举的值来消除{}dict,正如maddephysist所建议的:

# ingredients.py

class Ingredient(object):
    pass    

class Spam(Ingredient):
    pass

class Beans(Ingredient):
    pass

class Egg(Ingredient):
    pass

class IngredientType(Enum):
    SPAM = Spam
    BEANS = Beans
    EGG = Egg

    @staticmethod
    def make(ingredient_type):
        return ingredient_type.value()

以及客户代码

 from ingredients import IngredientType
 egg = IngredientType.make(IngredientType.EGG)

但我也不认为这有什么好处

编辑:你提到:

I am trying to implement the factory pattern, with the intent of hiding the creation of objects away. The user of the factory then just handles 'Ingredients' without knowledge of the concrete type

用户仍然需要指定他想要什么样的成分(参数ingredient_type),所以我不确定我是否理解这里的好处。你的真正的用例到底是什么?(编出来的/呆板的例子的问题是,它们不能讲述整个故事)。在

相关问题 更多 >