2016-04-19 7 views
2

使いやすい抽象ファクトリを実装する際に問題があります。具体的な工場をこのように定義することができるようにメタクラスを使用したPythonのファクトリパターン実装

ゴール

class MyConcreteFactory(...): 
    @classmethod 
    def __load(cls, key): 
     obj = ... # Loading instructions here 
     return obj 

concretreファクトリを使用できるようにするには、このよう

obj = MyConcreteFactory[key] 

私の試み

私が試しましたブラケット演算子をオーバーライドしてカプセル化するファクトリのメタクラスを定義する電子工場パターン:と呼ばれる__loadメソッドはメタクラスではなく具体的​​なクラスから1から1であるので、

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) 

問題

これが失敗しました。結果は次のとおりです。

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_エラーが取り除かれます(サブクラスで '__getitem__'をどのように使うかによって' __resources'もあるかもしれませんが)。 – mgilson

答えて

1

あなたはメタクラスで@classmethodを使用しないでください。

def __getitem__(cls, key): 

が実際にクラスであり:メタクラスのインスタンスは、クラスので、それ自体で

@classmethod 
def __getitem__(metacls, key): 

は、最初の引数としてメタクラスを取得します。

私はメタクラスがこの問題をはるかに複雑にすると信じています。より基本的なクラスを作成し、それに応じてサブクラス化し、サブクラスのインスタンスをファクトリとして使用する方がより現実的な方法だと思います。

+0

あなたの助けを借りてTyは問題を解決しますが、私はファクトリブラケット演算子を上書きして、それらを使用して定義するようにしたいと考えました。メタクラスなしでこれを行う方法はありますか? –

関連する問題