如何创建多态数据类构造函数方法



我有3个数据类对象说:

class Message1:
def __init__(a):
...
class Message2:
def __init__(d,e,f):
...
class Message3:
def __init__(g,i):
...

对于这3个消息,我想做一个工厂类型的方法,如果它成功,它可以返回三个对象中的一个,如果没有,它应该返回它识别为要创建的正确消息,但在创建时失败,或者它应该通知用户它不能创建任何消息。有什么面向对象的模式吗?

我最初的想法是做一个:

def factory_method(**parameters):
try:
Message1(**parameters)
except TypeError:
try:
Message2(**parameters)
except:
try:
Message3(**parameters)
except:
print("Could not deduce message type")

我对这个想法的问题是:

  1. 这不是一个动态可扩展的解决方案,对于我引入的每个新消息类,我需要添加一个新的try catch块
  2. 如果整个嵌套块结构失败,我没有反馈为什么,参数是正确的消息之一,但错误的值,或者它是简单的胡言乱语?

我意识到这可能是基于什么是最好的结果的一些意见。同时,解决方案可能不太优雅,最简单的方法是告诉factory_method初始化哪种消息。如有任何建议或想法,我将不胜感激。

如果您不能将它们全部连接到一个类中,并且您不能将调用指向单个类,则会将参数匹配到可能的类。要使其工作,需要使用类型提示和"代理"。课程是必需的。这个例子假设任何一个类都不包含__init__(*args, **kwargs),并且要添加一个新类,您只需将其添加到Message.msg_cls,如果您不想手动添加每个类,您可以计算全局作用域。

class Message1:
def __init__(self, a: int, alt=None, num=10):
print('Message 1')
class Message2:
def __init__(self, d: str, e: str, f: int):
print('Message 2')
class Message3:
def __init__(self, g: int, i: any):
print('Message 3')

class Message:
msg_cls = (
Message1,
Message2,
Message3
)
@staticmethod
def eq_kwargs(cls, kwargs):
cls_kwargs = cls.__init__.__defaults__
if cls_kwargs is None:
if len(kwargs) > 0:
return False
else:
return True
cls_astr = cls.__init__.__code__
kw_types = [type(t) for t in cls_kwargs]
for k in kwargs:
if k in cls_astr.co_varnames:
if type(kwargs[k]) in kw_types:
kw_types.remove(type(kwargs[k]))
else:
if type(None) in kw_types:
kw_types.remove(type(None))
else:
return False
else:
return False
return True
@staticmethod
def eq_args(cls, args):
cls_args = cls.__init__.__annotations__
if len(cls_args) != len(args):
return False
for a, b in zip(args, cls_args):
if type(a) != cls_args[b] and cls_args[b] != any:
return False
return True
def __new__(cls, *args, **kwargs):
for mc in Message.msg_cls:
if Message.eq_args(mc, args):
if Message.eq_kwargs(mc, kwargs):
return mc(*args, **kwargs)
raise ValueError('Message.__new__, no match')
if __name__ == '__main__':
ms_1_a = Message(1, alt='a')
ms_1_b = Message(2, alt='a', num=5)
ms_2 = Message('X', 'Y', 5)
ms_3_a = Message(1, [1, 4])
ms_3_b = Message(2, Message(10))