Refactoring large constructors

We have several objects in our domain model with what you comically call abusive big constructors, so big that IntelliSense refuses to try to show all this to you ...

Derive a type with 50 arguments, mainly type values, with several reference types:

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

I will say it now, this type cannot change. The type itself logically represents one entity that turns out to be heavy. Callers creating this type provide most arguments from several sources, although some of them are defaulted. Perhaps there is a pattern for sources that will be provided for construction instead of results.

However, what can change is how the type is created. We currently have sections of code that suffer from:

One immediate answer is to use optional parameters for default values ​​and named arguments to help with merging. We do this to some extent on other types, it works fine.

However, it seems that this is halfway to full refactoring.

Another obvious solution is to reduce constructor parameters with container types that have properties for constructor arguments. This nicely decorates the constructors and allows you to embed the default values ​​in containers, but essentially transfers the problem to a different type and, possibly, is the same as using optional / named parameters.

There is also the concept of Fluent constructors ... for each property ( WithIntA , WithIntB ) as well as for the container type ( WithTheseInts(IntContainer c) ). Personally, I like this approach from the caller, but again, on a big type, it becomes verbose and feels as if I just moved the problem, and not solved it.

My question is, if there is someone in this mess, there is: - Is this a viable refactoring tactic for the problem? Please outline any answer with some relevant experience, pitfalls or criticism. I tend to Fluent materials because I think it looks cool and is quite readable and friendly.

It seems to me that I lack the Holy Grail of restructuring the constructor, so I am open to suggestions. Of course, this may just be the unfortunate and inevitable side effect of having a type with these many properties in the first place ...

+7
source share
3 answers

Obviously, there is not much context here, but with 50+ parameters, my interpretation is that this class does too much and is too complicated. I would start by looking for ways to divide pieces into simpler, more focused types, and then encapsulate instances of each of these concepts in a composite class. So it is done:

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

where only the logic necessary for the coordination between the concepts remains in MyLegacyType (any logic related to SomeConcept goes there, etc.).

This is different from your "reduce constructor options with container types that have properties for constructor arguments" because we fundamentally restructure the logic, and not just use the object to replace the constructor arguments.

+12
source

I would go with container types and use the direct assignment of C # 4.0 properties. Thus, you can easily use Intellisense for the resulting type, while maintaining a decent decoupling from the original type.

For example:

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

And then:

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

There is one thing that I'm not sure about your question about, and why do you want all such parameters in the constructor? Do you use all the parameters in the constructor code? Your intellisense problem is probably due to having too many parameters for one method. Having a large number of fields / properties of the same type will not cause any problems.

It seems that you have seen some ways to control the number of arguments, but if you can explain why you need to get them all in the constructor, we can think outside this field. There might be something to see.

+1
source

All Articles