Sign in to follow this  
Extrakun

Is there a design pattern for functions with many parameters?

Recommended Posts

I currently have a function that looks like this
public function CalculateXPGained(Skill s, int modifier, float multiplier, float time, IGraphFunction XPGraph);
This gets kind of troublesome over time; I could bundle all the parameters into a structure or class but that would increase coupling. Is there a pattern in which one could pass in a large number of parameters to a function?

Share this post


Link to post
Share on other sites
The typical approach is to package the parameters in a structure; this of course assumes that you can't simply reduce the number of parameters by rearranging the function a bit.

There's basically two approaches you can take: create a POD structure of the parameters you need and pass that structure into a free function; or wrap up a set of related values into a class and make the "calculate" function be a member function of that class. It should be fairly clear which method you would want to use in various cases.


As for the coupling issue - there's nothing wrong with tight coupling when that is how the domain data works. If two pieces of code are deeply interrelated, that's OK. The problem arises when you have two bits of code (or data) which are not related that are coupled together. It's coupling between unrelated areas that you want to avoid.

Share this post


Link to post
Share on other sites
Another way to deal with this is to have a number of SkillModifier classes, which can take appropriate values as properties.

Then you can just call the method on the skill modifier (with only the necessary data), and it will handle the rest for you.

Share this post


Link to post
Share on other sites
This isn't based on a pattern per se, but rather a way to accomplish it.

If you were using C/C++ (which I think you are using VB based on your function declaration), this idea might be a little excessive as it destroys compile time type safety, but you could just pass around vectors of boost::any's. Each function would then have a little more overhead in terms of checking for expected parameters and recasting into the correct type, but it would solve the problem of an arbitrary amount of parameters.

I'm not saying it's a good idea design wise, but it is an idea that is different from what's been mentioned so far. The idea would also work in weakly typed languages, but I'm not sure if you could use a VB Variant to get the job done. It would work in Java as you can simply pass an array of arbitrary Objects, and I don't know off hand of a way it'd work in C#.

Share this post


Link to post
Share on other sites
Quote:
Original post by Extrakun
This gets kind of troublesome over time

Can you explain how this becomes troublesome?
Personally I see no problem with the amount of parameters in your function, in fact it looks good to me. Just from seeing the function prototype I have a good idea on what the function does and what is required; as opposed to something like


public function CalculateXPGained(XP_structure xp);




Off course there is a limit to how many parameters should really be used, but if you have so many then maybe the function needs refactoring; yet not in this case IMHO.

Share this post


Link to post
Share on other sites
Quote:
Original post by ApochPiQ
The typical approach is to package the parameters in a structure; this of course assumes that you can't simply reduce the number of parameters by rearranging the function a bit.

There's basically two approaches you can take: create a POD structure of the parameters you need and pass that structure into a free function; or wrap up a set of related values into a class and make the "calculate" function be a member function of that class. It should be fairly clear which method you would want to use in various cases.


As for the coupling issue - there's nothing wrong with tight coupling when that is how the domain data works. If two pieces of code are deeply interrelated, that's OK. The problem arises when you have two bits of code (or data) which are not related that are coupled together. It's coupling between unrelated areas that you want to avoid.


QFE. Also, 5 parameters is not that many. :)

But also consider doing some refactoring. Maybe you have one function that takes the modifier, multiplier and time and synthesizes an "effort" value, and then another that takes effort and the Skill and comes up with two x-values for the function, and then you call Integrate() or something in the IGraphFunction interface.

Share this post


Link to post
Share on other sites
Thanks, the "create it as a class" approach is one thing I missed out on; it is actually a static function intended for utility usage. One issue though is that the client of the class must remember to set all the parameters (or I have to provide defaults).

Shouldn't the structure have an interface as well, or is that carrying it a bit too far?

As I am using C#, I can pack everything into a dictionary and type-cast it, but I feel uneasy about this as missing a parameter will cause a mistake.

I believe having a class with defaults and allowing the client to change the specific would work...

Share this post


Link to post
Share on other sites
Just set up the constructor so that it requires all the parameters you need; that way you can ensure that nobody creates the parameter data without filling in all the fields. You can even set up multiple constructors for different combinations of required and optional fields, if you need that degree of flexibility.

I see no reason why you can't just set all the fields up as public members of the class/structure, so you really don't need to have any kind of interface beyond the constructor(s).

Share this post


Link to post
Share on other sites
Quote:
Original post by Extrakun
Shouldn't the structure have an interface as well, or is that carrying it a bit too far?

As I am using C#, I can pack everything into a dictionary and type-cast it, but I feel uneasy about this as missing a parameter will cause a mistake.

I believe having a class with defaults and allowing the client to change the specific would work...

KISS. How many places in your code call CalculateXPGained? How many programmers will write code involving it? How obscure would bugs caused by omitted parameters be?

Share this post


Link to post
Share on other sites
Quote:
Original post by Extrakun
Is there a pattern in which one could pass in a large number of parameters to a function?


Quote:
Original post by ApochPiQ
package the parameters in a structure


Quote:
Original post by Extrakun
the client of the class must remember to set all the parameters


Quote:
Original post by ApochPiQ
Just set up the constructor so that it requires all the parameters you need

....wwwwait.

Share this post


Link to post
Share on other sites
Here's how I do it:

struct Sprite {
Sprite(const char *_path, float _tx=0, float _ty=0, float _tw=0, float _th=0) : path(_path), tx(_tx), ty(_ty), tw(_tw), th(_th) {
};

const char *path;
const float tx, ty;
float tw, th;
};

struct Rotate {
Rotate(float _a=0, float _cx=0, float _cy=0) : a(_a), cx(_cx), cy(_cy) {
};

float a;
float cx, cy;
};

namespace R {
void DrawSprite(Sprite *, float x, float y, float w, float h, const Rotate *r=NULL, float z=0);
}


So a call looks like
R::DrawSprite(&Sprite("bg.png"), 0, 0, 800, 600);

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this