Best Practice for Passing Many Arguments to Method

Best practice for passing many arguments to method?

In Effective Java, Chapter 7 (Methods), Item 40 (Design method signatures carefully), Bloch writes:

There are three techniques for shortening overly long parameter lists:

  • break the method into multiple methods, each which require only a subset of the parameters
  • create helper classes to hold group of parameters (typically static member classes)
  • adapt the Builder pattern from object construction to method invocation.

For more details, I encourage you to buy the book, it's really worth it.

Best practice: how to pass many arguments to a function?

I don't think this is really a StackOverflow question, more of a Software Engineering question. For example check out this question.

As far as whether or not this is a good design pattern, this is an excellent way to handle a large number of arguments. You mentioned that this isn't very efficient in terms of memory or speed, but I think you're making an improper micro-optimization.

As far as memory is concerned, the overhead of running the Python interpreter is going to dwarf the couple of extra bytes used by instantiating your class.

Unless you have run a profiler and determined that accessing members of that options class is slowing you down, I wouldn't worry about it. This is especially the case because you're using Python. If speed is a real concern, you should be using something else.

You may not be aware of this, but most of the large scale number crunching libraries for Python aren't actually written in Python, they're just wrappers around C/C++ libraries that are much faster.

I recommend reading this article, it is well established that "Premature optimization is the root of all evil".

Best practice to pass arguments

About the performance, two of them are the same. If you implement your function as

public printUsernameAndGroup(String username, String group){
sout(username);
sout(group);
}

You will access username and group attributes of your object before calling the function. Also when you implement it as

public printUsernameAndGroup(Application application){
sout(application.username);
sout(application.group);
}

You are just passing a copy of the reference of that object, not copying all the 10 fields, and again accessing two attributes of it.

But if you think about the ease of use, the second one will be more user friendly.

When a method has too many parameters?

There is no clear limit, but I am uncomfortable with more than 3-4 parameters. AFAIR Uncle Bob Martin in Clean Code recommends max 3.

There are several refactorings to reduce the number of method parameters (see Working Effectively with Legacy Code, by Michael Feathers for details). These come to my mind:

  • encapsulate many related parameters into a single object (e.g. instead of String surName, String firstName, String streetAddress, String phoneNumber pass a Person object containing these as fields)
  • pass parameters in the constructor or other method calls prior to the invocation of this method

How many parameters are too many?

When is something considered so obscene as to be something that can be regulated despite the 1st Amendment guarantee to free speech? According to Justice Potter Stewart, "I know it when I see it." The same holds here.

I hate making hard and fast rules like this because the answer changes not only depending on the size and scope of your project, but I think it changes even down to the module level. Depending on what your method is doing, or what the class is supposed to represent, it's quite possible that 2 arguments is too many and is a symptom of too much coupling.

I would suggest that by asking the question in the first place, and qualifying your question as much as you did, that you really know all of this. The best solution here is not to rely on a hard and fast number, but instead look towards design reviews and code reviews among your peers to identify areas where you have low cohesion and tight coupling.

Never be afraid to show your colleagues your work. If you are afraid to, that's probably the bigger sign that something is wrong with your code, and that you already know it.

What are the best practices for passing multiple variables to a function using PHP

Highly depends on the use case.

But here are some solutions to this problem.


Fixed Order

If the order is somewhat fixed and you never have a need to change it, then:

<?php

function fn($a1, $a2, $a3, $a4, $a5, $a6 = null, $a7 = "foo", $a8 = "bar", array $a9 = array()) {}

Pros

  • Self documenting
  • Type hinting
  • Default values

Cons

  • Fixed order

Array

If on the other hand the order is somewhat different all the time, use the array thingy.

<?php

function fn($a1, $a2, $a3, $a4, $a5, array $optional = array()) {}

fn("", "", "", "", "", array("arg9" => false));

Pros

  • Easy to use
  • No fixed order

Cons

  • Not self documenting
  • Costly to validate

Parameter Object

A parameter object is of course a valid solution as well, but impractical to handle:

<?php

class Args {

public $arg5 = "foo";

public $arg6 = "bar";

public $arg7 = null;

public $arg8 = array();

public $arg9 = true;

}

function fn($arg1, $arg2, $arg3, $arg4, $arg5, \Args $optional = null) {}

// Now comes the impractical part.
$optional = new Args();
$optional->arg9 = false;
fn("", "", "", "", "", $optional);

Pros

  • Self documenting
  • No fixed order

Cons

  • Highly impractical
  • Costly to validate

Array to Parameter Object

You could mix the two approaches:

<?php

class Args {

public $arg5 = "foo";

public $arg6 = "bar";

public $arg7 = null;

public $arg8 = array();

public $arg9 = true;

public __construct($args) {
foreach ($args as $property => $value) {
$this->"set{$property}"($value);
}
}

public function setArg5($value) {
if (is_string($value) === false) {
throw new \InvalidArgumentException;
}
$this->arg5 = $value;
}

// and so on ...

}

function fn($arg1, $arg2, $arg3, $arg4, $arg5, array $optional = null) {
if (isset($optional)) {
$optional = new Args($optional);
}
// ...
}

fn("", "", "", "", "", array("arg9" => false));

Pros

  • Easy validation
  • Separation of concern
  • Easy to pass along
  • Easy to handle
  • Possible to document the API

Cons

  • Still not possible to document it as good as the fixed args approach
  • Costly to validate

Variadics

There's a new feature in PHP 5.6 that you might find useful, variadics:

<?php

function fn($a1, $a2, $a3, $a4, $a5, ...$optional) {}

Pros

  • Very fast
  • Allows to build special APIs (e.g. database prepared statement binding)

Cons

  • Not easily documented
  • Costly to validate

Named Parameters

And we might see named parameters in the future.

Java: Sending Multiple Parameters to Method

The solution depends on the answer to the question - are all the parameters going to be the same type and if so will each be treated the same?

If the parameters are not the same type or more importantly are not going to be treated the same then you should use method overloading:

public class MyClass
{
public void doSomething(int i)
{
...
}

public void doSomething(int i, String s)
{
...
}

public void doSomething(int i, String s, boolean b)
{
...
}
}

If however each parameter is the same type and will be treated in the same way then you can use the variable args feature in Java:

public MyClass 
{
public void doSomething(int... integers)
{
for (int i : integers)
{
...
}
}
}

Obviously when using variable args you can access each arg by its index but I would advise against this as in most cases it hints at a problem in your design. Likewise, if you find yourself doing type checks as you iterate over the arguments then your design needs a review.

Best practice for passing multiple function arguments in C++

there are 5 client functions.

You might pass structure instead

template <typename Element>
struct Customization {
std::function<void(Element)> client_code1;
std::function<void(Element)> client_code2;
std::function<void(Element)> client_code3;
std::function<void(Foo)> client_code4;
std::function<void(Bar)> client_code5;
};

or even possibly an interface:

template <typename Element>
struct Customization {
virtual ~Customization() = default;
virtual void client_code1(Element) = 0;
virtual void client_code2(Element) = 0;
virtual void client_code3(Element) = 0;
virtual void client_code4(Foo) = 0;
virtual void client_code5(Bar) = 0;
};

and then

template<class Range, class Element>
void run_generic_algorithm(Range& r, const Customization <Element>& customization);

Most of the time I am not even specifying all the client functions, so I have to put in a lambda function that does nothing.

With previous comment, you might give default values to the member of previous structure.

Else you can add default value to argument or create overloads.

What's the best way to refactor a method that has too many (6+) parameters?

The best way would be to find ways to group the arguments together. This assumes, and really only works if, you would end up with multiple "groupings" of arguments.

For instance, if you are passing the specification for a rectangle, you can pass x, y, width, and height or you could just pass a rectangle object that contains x, y, width, and height.

Look for things like this when refactoring to clean it up somewhat. If the arguments really can't be combined, start looking at whether you have a violation of the Single Responsibility Principle.

best way to pass many arguments to a method in Java

You could make a builder for Obj, which will give you a more fluent way of constructing the Obj than using the static method in your question.

public class ObjBuilder {
private String a;
private String b;
private List<KeyValue> keyValues = new ArrayList<>();

private ObjBuilder() {}

public static ObjBuilder obj() {
return new ObjBuilder();
}

public ObjBuilder withA(String a) {
this.a = a;
return this;
}

public ObjBuilder withB(String b) {
this.b = b;
return this;
}

public ObjBuilder withKeyValue(KeyValue keyValue) {
this.keyValues.add(keyValue);
return this;
}

public Obj build() {
// whatever Obj.makeSomeObject does to create the Obj instance
}
}

Then when you need to create an Obj

Obj obj = ObjBuilder.obj()
.withA("some String")
.withB("some String")
.withKeyValue(new KeyValue("A", "B"))
.withKeyValue(new KeyValue("C", "D"))
.build();

Obviously using this over the static varargs method in your question is largely a stylistic choice



Related Topics



Leave a reply



Submit