我試圖實現一個易於使用的抽象工廠的問題。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