为了重构的目的,一个只有属性的类可以吗?

本文关键字:属性 一个 重构 | 更新日期: 2023-09-27 18:14:23

我有一个接受30个参数的方法。我将参数放入一个类中,这样我就可以将一个参数(类)传递到方法中。在重构的情况下,传递一个封装了所有参数的对象是完全正确的吗?

为了重构的目的,一个只有属性的类可以吗?

真是个好主意。这就是WCF中数据契约的典型方式。

这个模型的一个优点是,如果您添加一个新参数,类的消费者不需要仅仅为了添加参数而进行更改。

正如David Heffernan提到的,它可以帮助自我文档化代码:

FrobRequest frobRequest = new FrobRequest
{
    FrobTarget = "Joe",
    Url = new Uri("http://example.com"),
    Count = 42,
};
FrobResult frobResult = Frob(frobRequest);

虽然这里的其他答案正确地指出,传递一个类的实例比传递30个参数要好,但要注意,大量参数可能是潜在问题的征兆。

。,很多时候,静态方法的参数数量会增加,因为它们本来就应该是实例方法,而且你传递了很多信息,这些信息可以更容易地在该类的实例中维护。

或者,寻找方法将参数分组到更高抽象级别的对象中。在我看来,将一堆不相关的参数转储到单个类中是最后的手段。

参见How many parameters are too many?更多关于这方面的想法。

这是一个好的开始。但是现在您已经有了这个新类,可以考虑将代码从内到外翻过来。将以该类为参数的方法移动到新类中(当然,将原始类的实例作为参数传递)。现在,您已经在类中单独获得了一个大方法,将其分解为更小、更易于管理、更可测试的方法将更加容易。其中一些方法可能会移回原始类,但相当一部分方法可能会留在新类中。您已经超越了引入参数对象,而是用方法对象替换方法。

有30个参数的方法是一个非常强烈的信号,表明该方法太长、太复杂。很难调试,也很难测试。所以你应该做点什么,引入参数对象是一个很好的开始。

虽然重构为参数对象本身并不是一个坏主意,但它不应该被用来隐藏这样一个问题:一个需要从其他地方提供30条数据的类仍然可能是某种代码气味。引入参数对象重构可能应该被视为更广泛重构过程中的一个步骤,而不是该过程的结束。

它没有真正解决的一个问题是功能嫉妒。传递参数对象的类对另一个类的数据如此感兴趣,这一事实是否表明对该数据进行操作的方法可能应该移动到数据所在的位置?最好识别属于一起的方法和数据集群,并将它们分组到类中,从而增加封装并使您的代码更灵活。

在将行为和它所操作的数据分离成单独的单元的几次迭代之后,你应该会发现你不再有任何具有大量依赖关系的类,这总是一个更好的最终结果,因为它会使你的代码更灵活。

这是一个很好的主意,也是解决问题的一个很常见的方法。超过2或3个参数的方法越来越难理解。

将所有这些封装在一个类中可以使代码更清晰。因为你的属性有名字,所以你可以像这样编写自文档代码:

params.height = 42;
params.width = 666;
obj.doSomething(params);

当然,当你有很多参数时,基于位置识别的替代方法简直是可怕的。

另一个好处是可以在不强制更改所有调用站点的情况下向接口契约添加额外的参数。然而,这并不总是像看起来那么微不足道。如果不同的调用站点需要新参数的不同值,那么与基于参数的方法相比,查找这些值要困难得多。在基于参数的方法中,添加新参数强制在每个调用站点进行更改以提供新参数,并且可以让编译器完成查找所有参数的工作。

Martin Fowler在他的书Refactoring中称之为引入参数对象。有了这样的引用,很少有人会说这是一个坏主意。

30个参数太乱了。我认为有一个带有属性的类会更漂亮。您甚至可以为同一类别的参数组创建多个"参数类"。

你也可以考虑使用结构体来代替类。

但是你要做的事情很普通,也是个好主意!

无论是否进行重构,使用Plain Old Data类都是合理的。我很好奇你为什么会觉得不是。

也许c# 4.0的可选和命名参数是一个很好的替代方案?

无论如何,你描述的方法也可以很好地抽象程序的行为。例如,您可以在一个接口中有一个标准的SaveImage(ImageSaveParameters saveParams) -函数,其中ImageSaveParameters也是一个接口,并且可以根据图像格式具有附加参数。例如,JpegSaveParameters具有Quality -属性,而PngSaveParameters具有BitDepth -属性。

这是如何保存保存对话框在油漆。NET做到了,所以这是一个非常现实的例子。

如前所述:这是正确的一步,但也要考虑以下几点:

    你的方法可能太复杂(你应该考虑把它分成更多的方法,或者甚至把它变成一个单独的类)
  • 如果你为参数创建类,让它不可变
  • 如果许多参数可以为空或可以有一些默认值,您可能希望为您的类使用构建器模式。

这里有很多很棒的答案。我想提出我的意见。

Parameter对象是一个很好的开始。但是还有更多的事情可以做。考虑以下(ruby示例):

/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

这样的用法将帮助您发现向这些参数对象添加有意义行为的可能性。您会发现它们很快就能摆脱最初的Data Class气味,让您感到舒适。: -)