【发布时间】:2012-01-16 17:50:23
【问题描述】:
我的代码库是 Python。假设我有一个相当通用的类,称为 Report。它需要大量的参数
class Report(object):
def __init__(self, title, data_source, columns, format, ...many more...)
而且有很多很多实例化的报告。这些实例化并非完全无关。许多报告共享一组相似的参数,只是略有不同,例如具有相同的 data_source 和列,但标题不同。
不是复制参数,而是应用了一些编程结构来使这种结构的表达更容易。我正在努力寻找一些帮助来整理我的头脑,以确定一些成语或设计模式。
如果报表的子类需要一些额外的处理代码,子类似乎是一个不错的选择。假设我们有一个 ExpenseReport 的子类别。
class ExpenseReport(Report):
def __init__(self, title, ... a small number of parameters ...)
# some parameters are fixed, while others are specific to this instance
super(ExpenseReport,self).__init__(
title,
EXPENSE_DATA_SOURCE,
EXPENSE_COLUMNS,
EXPENSE_FORMAT,
... a small number of parameters...)
def processing(self):
... extra processing specific to ExpenseReport ...
但在很多情况下,子类只是修复了一些参数,没有任何额外的处理。使用偏函数可以轻松完成。
ExpenseReport = functools.partial(Report,
data_source = EXPENSE_DATA_SOURCE,
columns = EXPENSE_COLUMNS,
format = EXPENSE_FORMAT,
)
在某些情况下,甚至没有任何区别。我们只需要将同一对象的 2 个副本用于不同的环境,例如嵌入到不同的页面中。
expense_report = Report("Total Expense", EXPENSE_DATA_SOURCE, ...)
page1.add(expense_report)
...
page2.add(clone(expense_report))
在我的代码库中,使用了一种丑陋的技术。因为我们需要为每个页面提供 2 个单独的实例,并且因为我们不想复制具有创建报告的长参数列表的代码,所以我们只需克隆(在 Python 中深度复制)第 2 页的报告。不仅需要克隆不明显,忽略克隆对象而是共享一个实例会在我们的系统中产生许多隐藏的问题和细微的错误。
在这种情况下有什么指导吗?子类、部分函数或其他成语?我的愿望是让这个结构轻而透明。我对子类稍有警惕,因为它可能会导致子类的丛林。并且它会诱导程序员添加特殊的处理代码,就像我在 ExpenseReport 中所做的那样。如果有需要,我宁愿分析代码,看看它是否可以泛化并推送到报告层。这样报表就变得更具表现力,无需在较低层进行特殊处理。
其他信息
我们确实使用关键字参数。问题更多在于如何管理和组织实例化。我们有大量具有通用模式的实例化:
expense_report = Report("Expense", data_source=EXPENSE, ..other common pattern..)
expense_report_usd = Report("USD Expense", data_source=EXPENSE, format=USD, ..other common pattern..)
expense_report_euro = Report("Euro Expense", data_source=EXPENSE, format=EURO, ..other common pattern..)
...
lot more reports
...
page1.add(expense_report_usd)
page2.add(expense_report_usd) # oops, page1 and page2 shared the same instance?!
...
lots of pages
...
【问题讨论】:
-
关于克隆及其问题。也许您可以使用关键字参数的副本?
report_args = dict(title='Some tile', data_source=..., columns=..., format=...)然后expense_report1 = Report(**report_args), expense_report2 = Report(**report_args) -
我不清楚,你使用什么类型的参数,但如果你有需要大量参数的方法,我认为是使用关键字参数的情况。 SO question中的一些很好的例子
标签: python class design-patterns