python - 在创建动态子类型时摆脱“if”语句
问题描述
这是一个主要关于设计的问题。
让我们假设我们有一个类,它的作用是通过它正在迭代的一些参数来启动某种类型的不同子类。当__init__
方法为每个子类型接收不同的参数时,问题就出现了。有什么方法可以避免if
函数内部的语句初始化类只是为了知道要传入哪些参数?也许是一些我不知道的设计模式。或者它是一个糟糕设计的结果?
下面是我的意思的一个例子。请注意其中包含 if...else... 的管理静态方法,如果有更多类型的工人,我们将有更多的 if's,这是我试图避免的。请记住,示例很少,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
语句只会移动到那里,它不会解决任何问题。
谢谢!
解决方案
一种方法是向 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
很大(和/或有很多子类) ,嵌套循环可能会很慢
推荐阅读
- elasticsearch - 使用两个过滤器,字段的值和时间戳在 kibana 中的字符串字段上创建 URL
- regex - 如何匹配以 2 位数字结尾的 10 字符字符串?
- jquery - 使用 jquery 从复选框形成 API 调用请求
- javascript - 对象的属性未定义,即使对象上的 console.log 显示属性值
- javascript - 如何在某些部分隐藏/显示固定元素?
- ruby-on-rails - 葡萄如何动态设置参数值
- xpages - 将多个 NotesRichText 字段附加到文件下载控件
- java - 如何在eclipse`中做项目结构“src/main/java”?
- java - Vaadin WebApplication - 可以离线模式吗?
- arrays - 将十六进制值的字符串转换为 []byte 表示