2016-04-19 81 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爲您提供幫助,它解決了問題(+修復問題),但我想覆蓋工廠支架操作員以使其能夠使用和定義。沒有元類的方法嗎? –