Function that requires many parameters

I have a problem related to this:

Are there guidelines on how many parameters a function should accept?

In my case, I have a function that describes a rounded rectangle. The caller specifies

• An integer which determines how the rectangle should be merged into previously created shapes
• An Anchor, which is a point that is used for alignment (right, left, top, bottom etc). (0,-1) means that position (next parameter) describes the top, middle point of the rectangle.
• The position of the rectangle
• Width and height
• Corner radius

Should I use Parameter Object pattern in this case? It is hard to see how these parameters are related

-
As the saying goes: if you have a function taking 10 parameters, you probably forgot a few. – Joris Timmermans Sep 12 '12 at 15:45
The more parameters of the same type you use, the more likelihood someone will transpose them, e.g. swapping the int X and int Y coordinates. I have no idea how people control lots of parameters without type safety. Not sure what language you are using, but Java has a Point and a Point2D that can be used to avoid some confusion. – GlenPeterson Sep 12 '12 at 16:16

2 Answers

I prefer to keep the number of function arguments to four or fewer.

It sounds like the function "merges" a rounded rectangle it into some environment. The first thing that comes to mind is to separate the activity into two parts: defining the rectangle, and then merging it.

``````rr = roundedRectangle(width, height, cornerRadius)
environment.merge(rr, how, alignment, where)
``````

If the cornerRadius has a convenient default (e.g. zero), then you could switch to:

``````rr = roundedRectangle(width, height).setCornerRadius(r)
``````

If the number of options to merge increases, then you could create a parameter object for those:

``````mm = mergeMethod(position).setAlignment(topCenter).setBehavior(...)
env.merge(rr, mm)
``````

This allows for a natural extension to other shapes. It would be poor practice to repeat the list of mergeMethod arguments once for every shape that could be created.

=== Dan's Addendum ===

When splitting actions in this way, it is important to avoid introducing undesirable order dependencies. Any values not specified when an instance is created should have useful defaults. If you remove the `cornerRadius` argument from the `roundedRectangle` constructor, you must set a useful default. It must be sensible to write either `rr = roundedRectangle(width, height)` or `rr = roundedRectangle(width, height).setCornerRadius(...)`.

-
very good answer, +1 to split functionality in methods as basic as possible – mcwise Sep 12 '12 at 16:31
However, you do want to watch out for situations where "you have to call `Y` after `X`" because an interface can't enforce that. – Dan Sep 12 '12 at 18:49

Not all the parameters are related, but some subsets are. You could have 3 parameters:

• Merge behavior
• Position (base position & anchor point)
• Rectangle description (height, width, corner radius)

Or, it might make more sense that anchor point is part of the rectangle description.

-