我是Python的新手,需要一些建议来实现下面的场景.
我在两个不同的注册商处有两个用于管理域名的课程.两者都具有相同的界面,例如
class RegistrarA(Object): def __init__(self, domain): self.domain = domain def lookup(self): ... def register(self, info): ...
和
class RegistrarB(object): def __init__(self, domain): self.domain = domain def lookup(self): ... def register(self, info): ...
我想创建一个Domain类,给定一个域名,根据扩展名加载正确的注册器类,例如
com = Domain('test.com') #load RegistrarA com.lookup() biz = Domain('test.biz') #load RegistrarB biz.lookup()
我知道这可以使用工厂函数来完成(见下文),但这是最好的方法吗?还是有更好的方法使用OOP功能?
def factory(domain): if ...: return RegistrarA(domain) else: return RegistrarB(domain)
Alec Thomas.. 75
我认为使用函数很好.
更有趣的问题是如何确定要加载哪个注册商?一种选择是拥有一个抽象的基础注册器类,具体实现子类,然后迭代__subclasses__()
调用一个is_registrar_for()
类方法:
class Registrar(object): def __init__(self, domain): self.domain = domain class RegistrarA(Registrar): @classmethod def is_registrar_for(cls, domain): return domain == 'foo.com' class RegistrarB(Registrar): @classmethod def is_registrar_for(cls, domain): return domain == 'bar.com' def Domain(domain): for cls in Registrar.__subclasses__(): if cls.is_registrar_for(domain): return cls(domain) raise ValueError print Domain('foo.com') print Domain('bar.com')
这将允许您透明地添加新的Registrar
s并将每个支持的域的决定委托给它们.
我认为使用函数很好.
更有趣的问题是如何确定要加载哪个注册商?一种选择是拥有一个抽象的基础注册器类,具体实现子类,然后迭代__subclasses__()
调用一个is_registrar_for()
类方法:
class Registrar(object): def __init__(self, domain): self.domain = domain class RegistrarA(Registrar): @classmethod def is_registrar_for(cls, domain): return domain == 'foo.com' class RegistrarB(Registrar): @classmethod def is_registrar_for(cls, domain): return domain == 'bar.com' def Domain(domain): for cls in Registrar.__subclasses__(): if cls.is_registrar_for(domain): return cls(domain) raise ValueError print Domain('foo.com') print Domain('bar.com')
这将允许您透明地添加新的Registrar
s并将每个支持的域的决定委托给它们.
假设您需要为不同的注册商提供单独的类(虽然在您的示例中并不明显),但您的解决方案看起来还不错,尽管RegistrarA和RegistrarB可能共享功能并且可以从Abstract Base Class派生.
作为您的factory
函数的替代方法,您可以指定一个dict,映射到您的注册器类:
Registrar = {'test.com': RegistrarA, 'test.biz': RegistrarB}
然后:
registrar = Registrar['test.com'](domain)
一个狡辩:你不是在这里做一个类工厂,因为你正在返回实例而不是类.
在Python中,您可以直接更改实际的类:
class Domain(object): def __init__(self, domain): self.domain = domain if ...: self.__class__ = RegistrarA else: self.__class__ = RegistrarB
接下来会有效.
com = Domain('test.com') #load RegistrarA com.lookup()
我成功地使用了这种方法.
您可以创建一个"包装器"类并重载其__new__()
方法以返回专用子类的实例,例如:
class Registrar(object): def __new__(self, domain): if ...: return RegistrarA(domain) elif ...: return RegistrarB(domain) else: raise Exception()
另外,为了处理非互斥条件,在其他答案中提出的问题,首先要问自己的问题是你是否想要扮演调度员角色的包装类来管理条件,或者它会将它委托给专门的类.我可以建议一个共享机制,其中专门的类定义它们自己的条件,但是包装器执行验证,就像这样(假设每个专用类公开一个类方法来验证它是否是特定域的注册器,is_registrar_for(. ..)如其他答案所示):
class Registrar(object): registrars = [RegistrarA, RegistrarB] def __new__(self, domain): matched_registrars = [r for r in self.registrars if r.is_registrar_for(domain)] if len(matched_registrars) > 1: raise Exception('More than one registrar matched!') elif len(matched_registrars) < 1: raise Exception('No registrar was matched!') else: return matched_registrars[0](domain)