[英]How to make a Python factory class
我希望能夠基於枚舉類創建對象,並使用字典。 像這樣:
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()
但是我得到了錯誤:
NameError: name 'IngredientFactory' is not defined
由於某些原因,無法創建字典。 我在哪里錯了?
Python不是Java,不需要將所有內容都放在類中。 這里的IngredientFactory
類沒有狀態,只有靜態方法,因此它實際上只是一個單例名稱空間,在python中,使用模塊作為單例名稱空間和普通函數可以正常完成此操作。 另外,由於Python類已經可以調用,因此將實例化包裝在函數中沒有任何意義。 簡單,直接的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()
和客戶端代碼:
import ingredients
egg = ingredients.make(ingredients.IngredientType.EGG)
# or much more simply:
egg = ingredients.Egg()
FWIW IngredientType
枚舉在這里並沒有帶來太多好處,甚至使事情變得更復雜,您必須使用純字符串:
# 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
,則至少可以通過使用類本身作為MadPhysicist建議的枚舉值來擺脫choices
字典:
# 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)
但我真的也看不到任何好處
編輯:您提到:
我試圖實現工廠模式,以隱藏對象的創建。 然后,工廠的用戶無需了解具體類型就可以處理“成分”
用戶仍然必須指定他想要哪種食材( ingredient_type
參數),因此我不確定我在這里是否了解好處。 您實際的用例是什么? (編造/精簡示例的問題在於它們無法說明全部內容)。
將您的映射放置在類的末尾,並直接引用方法,因為它們位於同一名稱空間中:
choice = {
IngredientType.SPAM: makeSpam,
IngredientType.BAKED_BEANS: makeBakedBeans,
IngredientType.EGG: makeEgg
}
直到類主體中的所有代碼都不會創建類對象,因此您無法訪問類本身。 但是,由於類主體是在專用名稱空間中處理的,因此您可以訪問到此為止定義的任何屬性(這就是為什么必須在映射末尾進行映射的原因)。 還要注意,雖然您可以訪問全局變量和內置插件,但不能訪問封閉類或函數的名稱空間。
這是來自官方文檔的詳細但仍介紹性的解釋,說明了如何執行類: https : //docs.python.org/3/tutorial/classes.html#a-first-look-at-classes
看了布魯斯·埃克爾的書后,我想到了:
#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()
這使用戶可以從枚舉中選擇類類型,並阻止任何其他類型。 這也意味着用戶不太可能寫出帶有拼寫錯誤的“壞字符串”。 他們只是使用枚舉。 然后,測試的輸出如下所示:
Circle.draw
Circle.erase
Circle.draw
Circle.erase
Square.draw
Square.erase
Square.draw
Square.erase
Circle.draw
Circle.erase
Circle.draw
Circle.erase
Square.draw
Square.erase
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.