主要是关于设计的问题。
让我们假设有一个类,该类具有通过其迭代通过的某些参数来初始化特定类型的不同子类的作用。当__init__
方法为每个子类型接收不同的参数时,就会出现问题。有什么方法可以避免函数内部的if
语句初始化类,以便仅知道要传入的参数?也许我不知道一些设计模式。还是设计不良的结果?
下面是我的意思的一个例子。请注意其中包含if ... else ...的manage static方法,并且如果有更多类型的worker,我们将拥有更多ifs,这就是我要避免的方法。
请记住,该示例是最少的,而if
语句可能要复杂得多。
from abc import ABCMeta
class BaseWorker(metaclass=ABCMeta):
def work(self):
pass
class Worker1(BaseWorker):
def __init__(self, name):
self.name = name
def work(self):
pass
class Worker2(BaseWorker):
def __init__(self, name, age):
self.name = name
self.age = age
def work(self):
pass
class Manager(object):
@staticmethod
def manage(attributes_list):
for attributes in attributes_list:
if "age" in attributes:
w = Worker2(name=attributes["name"], age=attributes["age"])
else:
w = Worker1(name=attributes["name"])
w.work()
if __name__ == '__main__':
dynamic_attributes = [
{"name": "davay"},
{"age": "55", "name": "ok"},
# and so on...
]
Manager.manage(dynamic_attributes)
所需的解决方案应该是
@staticmethod
def desired_manage(attributes_list):
for attributes in attributes_list:
w = worker_factory(attributes)
w.work()
**请注意,worker_factory
只是解决此问题的方式的任意名称,并不意味着工厂模式是可行的方式。
甚至更少,如果我们尝试工厂模式,从我看到的情况来看,if
语句将仅移动到那里,将无法解决任何问题。
谢谢!
答案 0 :(得分:1)
一种方法是在Manager中注册每个子类,以及确定该子类是否应实例化的可调用对象。
类似的东西(未经测试):
class Manager(object):
_registry = []
_default = None
@classmethod
def register(cls, callable, klass):
cls._registry.append((callable, klass))
return
@classmethod
def register_default(cls, klass):
cls._default = klass
return
@staticmethod
def manage(attributes_list):
for attributes in attributes_list:
for callable, klass in Manager._registry:
if callable(attributes):
w = klass(**attributes)
break
else:
w = Manager._default(**attrs)
w.work()
class BaseWorker(metaclass=ABCMeta):
def work(self):
pass
class Worker1(BaseWorker):
def __init__(self, name):
self.name = name
Manager.register_default(Worker1)
class Worker2(BaseWorker):
def __init__(self, name, age):
self.name = name
self.age = age
Manager.register(Worker2, lambda attrs: 'age' in attrs)
此方法有一些缺点:
'name' in attrs and 'age' in attrs
这样的宽松条件之前先测试更严格的条件(例如'name' in attrs
)。如果在不同的模块中定义了子类,则可能具有挑战性。也许为每个(callable, klass)
元组添加一个优先级,可用于对注册表进行排序attributes_list
大(和/或有很多子类),则嵌套循环可能会很慢答案 1 :(得分:0)
如果子类最后将共享工作方法,则您不需要此子类,并且实现它们将是错误的设计,从而不必要地增加了难度。您可以在 init 中使用默认值作为不需要的参数,然后它可以为每个子类型接收不同的参数而无需抱怨。
from abc import ABCMeta
class BaseWorker(metaclass=ABCMeta):
def work(self):
pass
class Worker(BaseWorker):
def __init__(self, name, age=None, address=None, sex=None):
self.name = name
self.age = age
address= address
sex= sex
def work(self):
pass
class Manager(object):
@staticmethod
def manage(attributes_list):
for attributes in attributes_list:
w = Worker(**attributes)
w.work()
if __name__ == '__main__':
dynamic_attributes = [
{"name": "davay"},
{"name": "aa", "age": "55"},
{"name": "bb", "sex": "female"},
{"name": "cc", "address": "123 street", "age": "43"},
# and so on...
]
Manager.manage(dynamic_attributes)