我有一个带有30个参数的方法。我把参数放到一个类中,这样我就可以只传递一个参数(类)到方法中。在重构的情况下,传入一个封装了所有参数的对象(即使它只包含这些参数)是否完全没有问题。
这是一个非常好的想法。例如,在 WCF 中数据契约就是这样完成的。
这个模型的一个优点是,如果添加一个新参数,类的使用者不需要仅仅为了添加参数而更改。
正如 David Heffernan 提到的,它可以帮助自我记录代码:
FrobRequest frobRequest = new FrobRequest { FrobTarget = "Joe", Url = new Uri("http://example.com"), Count = 42, }; FrobResult frobResult = Frob(frobRequest);
这是一个非常好的想法,也是解决这个问题的一个非常普遍的办法。参数超过2或3的方法越来越难以理解。
将所有这些封装在一个类中会使代码更加清晰。因为您的属性有名称,所以您可以像下面这样编写自记录代码:
params.height = 42; params.width = 666; obj.doSomething(params);
当您有很多参数时,基于位置标识的替代方案自然是非常可怕的。
另一个好处是,可以在接口契约中添加额外的参数,而不必在所有调用站点上进行更改。然而,这并不总是像看起来那样微不足道。如果不同的调用站点对新参数需要不同的值,那么比基于参数的方法更难找到它们。在基于参数的方法中,添加一个新参数会强制在每个调用站点更改以提供新参数,您可以让编译器完成查找所有参数的工作。
您还可以考虑使用结构而不是类。
但是你正在尝试做的是非常普通和伟大的想法!
30个参数就是一团糟。我觉得有一个带属性的类要漂亮得多。您甚至可以为属于同一类别的参数组创建多个“参数类”。
虽然这里的其他答案正确地指出,传递一个类的实例比传递30个参数要好,但要注意,大量的参数可能是一个潜在问题的症状。
例如,很多时候静态方法的参数数量会增加,因为它们本来就应该是实例方法,而且您传递的大量信息可以更容易地在该类的实例中维护。
或者,寻找将参数分组为更高抽象层的对象的方法。把一堆不相关的参数转储到一个类中是 IMO 的最后一招。
请参阅 多少参数才算太多?了解更多关于这方面的想法。
马丁 · 福勒在他的书《 重构》中称之为 引入参数对象。
虽然重构到一个参数对象本身并不是一个坏主意,但是它不应该被用来隐藏这样一个问题: 一个需要从其他地方提供30个数据的类可能仍然是代码味道的某种东西。引入参数对象重构可能应该被视为更广泛的重构过程中的一个步骤,而不是该过程的结束。
它没有真正解决的一个问题是特性嫉妒。传递参数对象的类对另一个类的数据如此感兴趣,这是否意味着对该数据进行操作的方法应该移动到数据所在的位置?最好确定属于一起的方法和数据集群,并将它们分组为类,从而增加封装并使代码更加灵活。
经过几次迭代,将行为和它操作的数据拆分成单独的单元,你会发现你不再有任何具有大量依赖关系的类,这总是一个更好的结果,因为它会使你的代码更加灵活。
这是个好的开始。但是现在已经有了这个新类,请考虑将代码由内向外翻转。将接受该类作为参数的方法移到新类中(当然,将原始类的实例作为参数传递)。现在您已经有了一个大方法,单独在一个类中,并且将它分解成更小的、更易于管理的、可测试的方法会更容易。其中一些方法可能会回到原来的类,但是一个合理的块可能会留在新类中。你已经从 引入参数对象转移到 用方法对象替换方法了。
拥有一个有30个参数的方法是一个非常强烈的信号,表明这个方法太长、太复杂。太难调试,太难测试。因此,您应该对此做些什么,并且“引入参数对象”是一个很好的起点。
无论是否进行重构,使用 原有资料类都是合理的。我很好奇你为什么会觉得不是。
也许 C # 4.0的可选参数和命名参数是一个很好的替代方案?
无论如何,您描述的方法也可以很好地抽象程序行为。例如,在接口中可以有一个标准的 SaveImage(ImageSaveParameters saveParams)函数,其中 ImageSaveParameters也是一个接口,并且根据图像格式可以有其他参数。例如,JpegSaveParameters有一个 Quality-属性,而 PngSaveParameters有一个 BitDepth-属性。
SaveImage(ImageSaveParameters saveParams)
ImageSaveParameters
JpegSaveParameters
Quality
PngSaveParameters
BitDepth
这就是 Paint.NET 中的保存对话框是如何做到的,所以它是一个非常真实的例子。
如前所述: 这是正确的步骤,但也要考虑到以下几点:
这里有很多很棒的答案,我想补充一下我的看法。
参数对象是一个很好的开始,但是还有更多的事情可以做:
/1/不要简单地对所有参数进行分组,而是看看是否可以对参数进行有意义的分组。您可能需要多个参数对象。
def display_line(startPoint, endPoint, option1, option2)
可能会变成
def display_line(line, display_options)
/2/参数对象的属性数可能比原来的参数数少。
def double_click?(cursor_location1, control1, cursor_location2, control2)
def double_click?(first_click_info, second_click_info) # MouseClickInfo being the parameter object type # having cursor_location and control_at_click as properties
这样的使用将帮助您发现向这些参数对象添加有意义的行为的可能性。你会发现,他们摆脱他们的初始 数据类气味更快,你的舒适。:--)