重构大型构造函数

我们的域模型中有一些对象,你可以说它们可以说是攻击性的大型构造函数,而且很大,以至于IntelliSense放弃了试图向你展示它…

提示具有50个左右参数的类型,主要是值类型,一些引用类型:

public class MyLegacyType { public MyLegacyType(int a1, int a2, int a3, ... int a50) // etc { } } 

我现在就说,没有这种类型不能改变。 类型本身在逻辑上代表一个实体,这恰好是属性重的。 构造此类型的调用者提供来自多个源的大多数参数,但有些是默认的。 也许有一种模式可以为建筑提供资源而不是结果。

但是,可以改变的是如何创建类型。 目前,我们的代码部分受到以下影响:

  • 该类型缺乏智能感知。
  • 丑陋且难以理解的代码。
  • 合并由于位置的Connascence导致的痛苦。

一个直接的答案是利用可选参数的默认值和命名参数来帮助合并。 我们在某种程度上对其他类型这样做,工作正常。

然而,感觉好像这是完全重构的一半。

另一个明显的解决方案是使用容器类型减少构造函数参数,这些容器类型具有以前是构造函数参数的属性。 这很好地整理了构造函数,并允许您在容器中嵌入默认值,但实际上将问题移到另一个类型上,并且可能与可选/命名参数用法相同。

还有Fluent构造函数的概念……在per属性( WithIntAWithIntB )或容器类型( WithTheseInts(IntContainer c) )的基础上。 就个人而言,我喜欢这种来自呼叫方的方法,但是在大型类型上它又变得冗长,感觉好像我刚刚移动了一个问题而不是解决问题。

我的问题是,如果有一个埋在这个烂摊子里的是: 这些问题的可行的重构策略是什么? 请通过一些相关经验,陷阱或批评来充实任何答案。 我倾向于Fluent的东西,因为我认为它看起来很酷,而且非常易读且易于合并。

我觉得好像我错过了构造函数重构的圣杯 – 所以我愿意接受建议。 当然,这也可能只是一个令人遗憾和不可避免的副作用,首先是拥有这么多属性的类型……

显然我们这里没有太多的背景,但是在50多个参数中,我的解释是这个课程做得太多,太复杂了。 我将首先寻找将块拆分为更简单,更集中的类型的方法 – 然后每个概念的实例封装到复合类中。 所以它变成了:

 public MyLegacyType(SomeConcept foo, AnotherConcept bar, ...) { } 

其中只有在概念之间编排所需的逻辑仍然存在于MyLegacyTypeMyLegacyType任何逻辑都去那里等)。

这与您的“使用具有以前构造函数参数的属性的容器类型的reduce构造函数参数”不同,因为我们从根本上重构逻辑 – 而不仅仅是使用对象来替换构造函数参数。

我会使用容器类型并使用C#4.0的直接属性赋值。 通过这种方式,可以轻松地在结果类型上使用Intellisense,同时仍然保留与原始类型的良好解耦。

例如:

 public class MyLegacyType { public MyLegacyType(MyConfiguration configuration) // etc { // ... } } public class MyConfiguration { public int Value1 { get; set; } public int Value2 { get; set; } // ... } 

然后:

 var myInstance = new MyLegacyType(new MyConfiguration { Value1 = 123, Value2 = 456 }); 

有一件事我不确定你的问题,这就是为什么你想在构造函数中使用所有这些参数? 您是否在构造函数代码中使用所有参数? 您对intellisense的问题可能来自于单个方法上的参数太多。 在单个类型上具有许多字段/属性不会导致任何问题。

看来你已经看到了一些管理args数量的方法,但是如果你能解释为什么你需要在构造函数中接收所有这些,我们可以在这个框之外思考。 可能有一些东西要看。