Is it OK to have a class with just properties for refactoring purposes?

C#OopRefactoring

C# Problem Overview


I have a method that takes 30 parameters. I took the parameters and put them into one class, so that I could just pass one parameter (the class) into the method. Is it perfectly fine in the case of refactoring to pass in an object that encapsulates all the parameters even if that is all it contains.

C# Solutions


Solution 1 - C#

That is a great idea. It is typically how data contracts are done in WCF for example.

One advantage of this model is that if you add a new parameter, the consumer of the class doesn't need to change just to add the parameter.

As David Heffernan mentions, it can help self document the code:

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

Solution 2 - C#

While other answers here are correctly point out that passing an instance of a class is better than passing 30 parameters, be aware that a large number of parameters may be a symptom of an underlying issue.

E.g., many times static methods grow in their number of parameters, because they should have been instance methods all along, and you are passing a lot of info that could more easily be maintained in an instance of that class.

Alternatively, look for ways to group the parameters into objects of a higher abstraction level. Dumping a bunch of unrelated parameters into a single class is a last resort IMO.

See https://stackoverflow.com/questions/174968/how-many-parameters-are-too-many for some more ideas on this.

Solution 3 - C#

It's a good start. But now that you've got that new class, consider turning your code inside-out. Move the method which takes that class as a parameter into your new class (of course, passing an instance of the original class as the parameter). Now you've got a big method, alone in a class, and it will be easier to tease it apart into smaller, more manageable, testable methods. Some of those methods might move back to the original class, but a fair chunk will probably stay in your new class. You've moved beyond Introduce Parameter Object on to Replace Method with Method Object.

Having a method with thirty parameters is a pretty strong sign that the method is too long and too complicated. Too hard to debug, too hard to test. So you should do something about it, and Introduce Parameter Object is a fine place to start.

Solution 4 - C#

Whilst refactoring to a Parameter Object isn't in itself a bad idea it shouldn't be used to hide the problem that a class that needs 30 pieces of data provided from elsewhere could still be something of a code smell. The Introduce Parameter Object refactoring should probably be regarded as a step along the way in a broader refactoring process rather than the end of that procedure.

One of the concerns that it doesn't really address is that of Feature Envy. Does the fact that the class being passed the Parameter Object is so interested in the data of another class not indicate that maybe the methods that operate on that data should be moved to where the data resides? It's really better to identify clusters of methods and data that belong together and group them into classes, thereby increasing encapsulation and making your code more flexible.

After several iterations of splitting off behaviour and the data it operates on into separate units you should find that you no longer have any classes with enormous numbers of dependencies which is always a better end result because it'll make your code more supple.

Solution 5 - C#

That is an excellent idea and a very common solution to the problem. Methods with more than 2 or 3 parameters get exponentially harder and harder to understand.

Encapsulating all this in a single class makes for much clearer code. Because your properties have names you can write self-documenting code like this:

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

Naturally when you have a lot of parameters the alternative based on positional identication is simply horrid.

Yet another benefit is that adding extra parameters to the interface contract can be done without forcing changes at all call sites. However, this is not always as trivial as it seems. If different call sites require different values for the new parameter, then it is harder to hunt them down than with the parameter based approach. In the parameter based approach, adding a new parameter forces a change at each call site to supply the new parameter and you can let the compiler do the work of finding them all.

Solution 6 - C#

Martin Fowler calls this Introduce Parameter Object in his book Refactoring. With that citation, few would call it a bad idea.

Solution 7 - C#

30 parameters is a mess. I think it's way prettier to have a class with the properties. You could even create multiple "parameter classes" for groups of parameters that fit in the same category.

Solution 8 - C#

You could also consider using a structure instead of a class.

But what you're trying to do is very common and a great idea!

Solution 9 - C#

It can be reasonable to use a Plain Old Data class whether you're refactoring or not. I'm curious as to why you thought it might not be.

Solution 10 - C#

Maybe C# 4.0's optional and named parameters be a good alternative to this?

Anyway, the method you are describing can also be good for abstracting the programs behavior. For example you could have one standard SaveImage(ImageSaveParameters saveParams)-function in an Interface where ImageSaveParameters also is an interface and can have additional parameters depending on the image-format. For example JpegSaveParameters has a Quality-property while PngSaveParameters has a BitDepth-property.

This is how the save save-dialog in Paint.NET does it so it is a very real life example.

Solution 11 - C#

As stated before: it is the right step to do, but consider the followings too:

  • your method might be too complex (you should consider dividing it into more methods, or even turn it into a separate class)

  • if you create the class for the parameters, make it immutable

  • if many of the parameters could be null or could have some default value, you might want to use the builder pattern for your class.

Solution 12 - C#

So many great answers here. I would like to add my two cents.

Parameter object is a good start. But there is more that could be done. Consider the following (ruby examples):

/1/ Instead of simply grouping all the parameters, see if there can be meaningful grouping of parameters. You might need more than one parameter object.

def display_line(startPoint, endPoint, option1, option2)

might become

def display_line(line, display_options)

/2/ Parameter object may have lesser number of properties than the original number of parameters.

def double_click?(cursor_location1, control1, cursor_location2, control2)

might become

def double_click?(first_click_info, second_click_info) 
                       # MouseClickInfo being the parameter object type 
                       # having cursor_location and control_at_click as properties

Such uses will help you discover possibilities of adding meaningful behavior to these parameter objects. You will find that they shake off their initial Data Class smell sooner to your comfort. :--)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionXaisoftView Question on Stackoverflow
Solution 1 - C#McKayView Answer on Stackoverflow
Solution 2 - C#D'Arcy RittichView Answer on Stackoverflow
Solution 3 - C#Carl ManasterView Answer on Stackoverflow
Solution 4 - C#Steve RowbothamView Answer on Stackoverflow
Solution 5 - C#David HeffernanView Answer on Stackoverflow
Solution 6 - C#Austin SalonenView Answer on Stackoverflow
Solution 7 - C#C.EvenhuisView Answer on Stackoverflow
Solution 8 - C#Tad DonagheView Answer on Stackoverflow
Solution 9 - C#Jon HannaView Answer on Stackoverflow
Solution 10 - C#loogView Answer on Stackoverflow
Solution 11 - C#GeTView Answer on Stackoverflow
Solution 12 - C#rpattabiView Answer on Stackoverflow