views:

69

answers:

4

For example, suppose I this:

class Gundam00 extends Gundam implements MobileSuit {
    ...

    public void fight(final List<MobileSuit> mobiruSuitso, final List<Gundam> theOtherDudes, final List<Person> casualities) {
        ....
    }
}

Suppose theOtherDudes and casualities parameters are optional. How can I make this method as clean as possible? I thought about having booleans indicating if they're null, and then checking them as needed.

I could also have different versions of the method for each combination of parameters but there would be a lot of code duplication I think.

Any suggestions?

A: 

I thought about having booleans indicating if they're null, and then checking them inside and reacting accordingly.

Or ... you could just check if they're null.

if(theOtherDudes == null)
    ...
Anon.
What I meant was doing `final boolean anyAllies = theOtherDudes == null` and checking that whenever I have to use that parameter. So that. I edited the post to make it clearer.
Setsuna F. Seiei
In the case of no "other dudes", You should probably pass in an empty collection instead of passing null.
Anon.
Now that you mention it, passing an empty collection sounds better.
Setsuna F. Seiei
+1  A: 

Add the methods. Overloading methods is generally an antipattern and a refactoring opportunity for someone else.

http://www.codinghorror.com/blog/2007/03/curlys-law-do-one-thing.html

le dorfier
+2  A: 

I find that past 2-3 arguments, the ability to remember what all the arguments to a function are suffers. And comprehensibility along with it.

Passing named arguments can help. Languages with a convenient hash-like literal syntax make this really easy. Take JavaScript:

g = new Gundam00();
g.fight({opponent: enemy, casualties: 'numerous'});

You can also take advantage of variable length argument features to work this in (treat odd arguments as names, even arguments as the actual parameters).

g.fight('opponent',enemy,'casualties', 'numerous');

And some languages actually support named arguments straight-out (see: http://en.wikipedia.org/wiki/Named_parameter#Use_in_programming_languages ).

Finally, you might want to consider adding other methods for this using what some call a Fluent Interface (http://en.wikipedia.org/wiki/Fluent_interface ). Basically, you've got method call which return the object itself, so you can chain calls together:

g.opponent(enemy).casualties('numerous').fight();

This might be the easiest option if you're working in a manifestly/statically-typed class-focused language.

Update

Responding to Setsuna's comment... in that last example, if you've got the luxury, you can make methods like opponent and casualties simple setters that don't affect any internal state or computation in any other way than setting a parameter for which they're named. They simply set internal properties up, and then all of the real work happens inside action methods like fight.

If you can't do that (or if you don't like writing methods whose operations are sub-atomic), you could stake out a half-way spot between this idea with the hash-like literal idea, and create your own collection class specifically for invoking named arguments:

n = new NArgs();  
g.fight(n.arg('opponent',enemy).arg('casualties','numerous').arg('motion','slow'));

A little more unwieldy, but it separates out the named arguments problem and lets you keep your methods a bit more atomic, and NArgs is probably something you could implement pretty easily just wrapping some methods around one type of Collection (HashTable?) or another that's available in your language.

Weston C
The last approach is what I had in mind at first - decorators - but the operations have to be performed simultaneously. So I couldn't think of a way of adding them. I'm sure there is, I'm just not used to this pattern.
Setsuna F. Seiei
You could just make `opponent` and `casualties` basic setters and leave the real work in `fight`... but if that doesn't work for your situation, you could make a named arguments class that uses some of that idea. I just updated my answer to reflect this.
Weston C
A: 

If there is only one "main method" in your class, then you can implement the optional arguments as getter/setter functions. Example:

public void setOtherDudes(final List<Gundam> theOtherDudes) {} // for input arguments
public List<Person> getCasualities() {} // for output arguments

And then, in your documentation, mention that if the caller has any optional input arguments it has to be passed in before calling fight(), and the optional output values will be available when fight() has been called.

This is worthwhile if there are dozens of optional arguments. Otherwise, I suggest overloading the method as the simplest way.

rwong