Согласен.
_IMPLEMENTATIONS лучше определить внутри класса фабрики.
Но __call__ __getattr__ лучше оставить, потому что в реализация может перекрывать больше чем один метод.
class Factory(object):
_IMPLEMENTATIONS = {}
def __init__(self, selector):
self.selector = selector
@classmethod
def register_implementation(cls, impl):
cls._IMPLEMENTATIONS[impl.name] = impl
def __call__(self):
return self._IMPLEMENTATIONS[self.selector(self.__class__)]
def __getattr__(self, name):
return getattr(self(), name)
class DefaultAvatar:
name = 'default'
def get_avatar_path(self, user, size=48):
return '/static/avatars/%s/%d' % (user.login, size,)
def get_avatar_something(self, user):
return 'something'
class Gravatar:
name = 'gravatar'
def get_avatar_path(self, user, size=48):
return 'http://www.gravatar.com/avatar/bla-bla?'
def get_avatar_something(self, user):
return 'gravatar'
implementation = 'default'
def implementation_selector(cls):
return implementation
class User(object):
avatar = Factory(implementation_selector)
def __init__(self, login, email):
self.login = login
self.email = email
def get_avatar_path(self, size=48):
return self.avatar.get_avatar_path(self, size)
def get_avatar_something(self):
return self.avatar.get_avatar_something(self)
# --------
defavatar = DefaultAvatar()
Factory.register_implementation(defavatar)
gravatar = Gravatar()
Factory.register_implementation(gravatar)
user1 = User('login', 'test@example.com')
user2 = User('test2', 'test2@example.com')
print user1.get_avatar_path()
print user1.get_avatar_something()
print user2.get_avatar_path()
print user2.get_avatar_something()
implementation = 'gravatar'
print user1.get_avatar_path()
print user1.get_avatar_something()
print user2.get_avatar_path()
print user2.get_avatar_something()
Еще возникла такая идея, для того чтобы базовый класс совсем ничего не знал о том какие фабрики и для чего он должен иметь построить структуру типа этой:
BaseClass
/ / |
/ / |
/ / |
Imp1 Impl2 | --- Factory
\ \ |
\ \ |
\ \ |
ReallyUsedClass
Фабрика будет создавать новые инстансы базового класса на основе добавленных в нее классов.
Прототип:
class Factory(list):
def __init__(self, BaseClass):
self.name = BaseClass.__name__ + "Factory"
self = [BaseClass]
def __call__(self, *argv, **kw):
cls = type(self.name, tuple(reversed(self)), {})
return cls(*argv, **kw)
# ----
class _User(object):
def __init__(self, login, email):
self.login = login
self.email = email
def method(self):
return 'original method'
def get_avatar_path(self, size=48):
return '/static/avatars/%s/%d' % (self.login, size,)
def do_something(self):
return 'do something'
User = Factory(_User)
# ----
class GravatarUser(_User):
def get_avatar_path(self, size=48):
return '/gravatar!!!'
User.append(GravatarUser)
class SomethingUser(_User):
def do_something(self):
return 'new do something!!!'
User.append(SomethingUser)
# --- используем где-то там далеко ---
u = User('test', 'test@example.com')
print u.get_avatar_path(96)
print u.method()
print u.do_something()