我试图实现一个易于使用的抽象工厂的问题。Python工厂模式实现与元类
目标
为了能够确定具体的工厂是这样的:
class MyConcreteFactory(...):
@classmethod
def __load(cls, key):
obj = ... # Loading instructions here
return obj
为了能够使用concretre工厂这样
obj = MyConcreteFactory[key]
我尝试
我试着为工厂定义一个元类,重载括号运算符并封装th Ë工厂模式:
class __FactoryMeta(type):
__ressources = {}
@classmethod
def __getitem__(cls, key):
if key not in cls.__ressources:
cls.__ressources[key] = cls.__load(key)
return cls.__ressources[key]
@classmethod
def __load(cls, key):
raise NotImplementedError
class ConcreteFactory(metaclass=__FactoryMeta):
@classmethod
def __load(cls, key):
return "toto"
a = ConcreteFactory["mykey"]
print(a)
问题
这种失败,因为叫__load方法是从元类的一个,而不是从一个具体的类。其结果是:
Traceback (most recent call last):
File "C:\Users\walter\workspace\Game\src\core\factories.py", line 34, in <module>
a = ConcreteFactory["mykey"]
File "C:\Users\walter\workspace\Game\src\core\factories.py", line 19, in __getitem__
cls.__ressources[key] = cls.__load(key)
File "C:\Users\walter\workspace\Game\src\core\factories.py", line 24, in __load
raise NotImplementedError
NotImplementedError
我试图从元类中删除__load方法,但后来我得到这个(预测的)错误:
Traceback (most recent call last):
File "C:\Users\walter\workspace\Game\src\core\factories.py", line 30, in <module>
a = ConcreteFactory["mykey"]
File "C:\Users\walter\workspace\Game\src\core\factories.py", line 19, in __getitem__
cls.__ressources[key] = cls.__load(key)
AttributeError: type object '__FactoryMeta' has no attribute '_FactoryMeta__load'
问题
有没有办法访问一个元类的类方法? 我错了,应该以其他方式做到这一点?那么这种方式?
解决方案
class __FactoryMeta(type):
ressources = {}
def __getitem__(cls, key):
if key not in cls.ressources:
cls.ressources[key] = cls.load(key)
return cls.ressources[key]
def load(cls, key):
raise NotImplementedError
class ConcreteFactory(metaclass=__FactoryMeta):
@classmethod
def load(cls, key):
return "toto"
a = ConcreteFactory["mykey"]
print(a)
至少有一部分问题是名称混乱,请参阅http://stackoverflow.com/q/7456807/3001761 – jonrsharpe
是不是一个元类(几乎)只有双下划线不是一个坏习惯的例子? –
Jon的正确。 '__name'被解释器弄坏了,目的是为了让超类无法访问。将'__load'改成'_load',你会摆脱_that_错误(尽管你也可能会用'__resources' - 也取决于你在子类中如何使用__getitem__')。 – mgilson