2016-04-19 58 views
2

我试图实现一个易于使用的抽象工厂的问题。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) 
+3

至少有一部分问题是名称混乱,请参阅http://stackoverflow.com/q/7456807/3001761 – jonrsharpe

+0

是不是一个元类(几乎)只有双下划线不是一个坏习惯的例子? –

+1

Jon的正确。 '__name'被解释器弄坏了,目的是为了让超类无法访问。将'__load'改成'_load',你会摆脱_that_错误(尽管你也可能会用'__resources' - 也取决于你在子类中如何使用__getitem__')。 – mgilson

回答

1

在元类,则不应使用@classmethod。元类的实例是类本身,以便:

def __getitem__(cls, key): 

实际上是类:

@classmethod 
def __getitem__(metacls, key): 

获取元类作为第一个参数。

此外,我认为元类使这个问题变得更加复杂。我相信一个更可行的方法是创建一个基本工厂类,相应地进行子类化,并将子类的实例用作工厂。

+0

Ty为您提供帮助,它解决了问题(+修复问题),但我想覆盖工厂支架操作员以使其能够使用和定义。没有元类的方法吗? –