开发者

How to deal with huge parameter lists?

开发者 https://www.devze.com 2023-04-02 18:43 出处:网络
So my main class was getting quite large so I decided to encapsulate the drawing of displays to its own class.

So my main class was getting quite large so I decided to encapsulate the drawing of displays to its own class.

Then, on the OnPaint event handler I call displayDrawer.Draw();

The only problem is that in order to draw something the method needs quite a few arguments.

For example, there are four boolean arguments specifying flags that affect drawing. Example: whether or not to draw at all (don't draw if the file isn't loaded), tints, which layers to draw, et cetera. Then of course there is the offsets that need to be passed. Depending on the offset of the horizontal and vertical scrollbars or the width and height of the display, the drawer needs to react accordingly.

The reason these all need to be passed is because the class does not have access to the form's controls. I rather not make the controls public or provide accessors and I don't want to pass the form either.

The obvious answer is to create either a class or struct filled with the values like this:

class Offsets
{
    public int horizontal, vertical, displayWidth, displayHeight;

    public Offsets(int horizontal, int vertical, int displayWidth, int displayHeight)
    {
        this.horizontal = horizontal;
        this.vertical = vertical;
        this.displayWidth = displayWidth;
        this.displayHeight = dis开发者_开发百科playHeight;
    }
}

class DrawingFlags
{
    public bool drawCurrentLayer, drawOtherLayers, drawDisplay;

    public DrawingFlags(bool drawCurrentLayer, bool drawOtherLayers, bool drawDisplay)
    {
        this.drawCurrentLayer = drawCurrentLayer;
        this.drawOtherLayers = drawOtherLayers;
        this.drawDisplay = drawDisplay;
    }
}

But is it all really worth it? These containers will only ever be used once in the program during that method call and then after that it's just more lines of code to have to sift through. Should I just bite the bullet and accept that this one method call has a lot of parameters?


Note that if you're just creating a class with public properties, but you are populating that class with a constructor that takes a dozen parameters, then you are just pushing the same method parameter complexity from one place to another, and you are adding more complexity by incorporating the properties. Only do this if you get a net gain.

For example, your class

class Offsets 
{
    public int horizontal, vertical, displayWidth, displayHeight;

    public Offsets(int horizontal, int vertical, int displayWidth, int displayHeight)
    {
        this.horizontal = horizontal;
        this.vertical = vertical;
        this.displayWidth = displayWidth;
        this.displayHeight = displayHeight;
    } 
}

can be modified to look like this:

class Offsets
{
    public int horizontal { get; set; }
    public int vertical { get; set; }
    public int displayWidth { get; set; }
    public int displayHeight { get; set; }
}

and can be populated like this

var offsets = new Offsets { horizontal = 10, vertical = 20 ... }

This is more readable, because you are giving a name to each parameter. It also intellisenses.

Note that if you're using C# 4.0, you don't have to do any of this, as you have the benefit of named and optional parameters:

var result = MyMethod(horizontal: 10, vertical: 20);


But is it all really worth it?

Yes, if, and only if, you end up copying that same (or a similar) method signature again or you have to pass in 8+ arguments calling that method throughout your code. If it is one method in one place that's called one or two times then I say move on, leave the argument list as it is currently, and never look back.

If you later decide that you have a couple of other types that will follow a similar pattern then yes, you should split out the options into a complex type. You can also create defaults as readonly members to make the default case easy, yet still allowing for different behavior in parts of the code that need it.

I am not big on over engineering, you should do what makes your life (and those to come after you...) easier. For one method, a long argument list is probably fine. If it grows in scope then it is time to refactor.


I think creating a class to group a bunch of parameters that you are passing into a function is fine, even if it is only ever for a single use in your application. It could be useful if you extend your accepting class and want to pass similar parameters to the child class in the future. It doesn't matter if you're passing one parameter or twenty-five, if your parameters can be grouped as a separate logical entity, then a class is never a bad choice in my opinion.

If you're really against creating a class for such a thing, you could always use an anonymous type... but I'd recommend you use just create the class for the benefits that will provide in flexibility and extensibility in the future.


If you are only using the container classes once, and only for the purpose of reducing the parameter list in one method of your app, from 7 parameters (the 4 offsets and 3 flags) to 2 parameters (your two container classes), then I would say it is not worth it.
It might be worth it if these container classes are useful in other areas of your application. There are many methods in the .NET framework with 7 parameters or more. It should not be a problem.


Another idea might be to pass a Dictionary or something similar. I was thinking HashMap in Java but I think Dictionary is the closest thing in C#.

0

精彩评论

暂无评论...
验证码 换一张
取 消