Question about eliminating conditional logic

A

Adam Sandler

Hello:

I'm having a hard time with implementing the notion of getting rid of
some "if then else" hell.

Given the following code sample:

if (i = 1)
{
method1(i);
}
else if (i = 2)
{
method2(i);
}
else if (i = 3)
{
method3(i);
}
else (i = 4)
{
method4(i);
}

I looked in Fowler's "Refactoring"... but replace conditional with
polymorphism doesn't seem to apply -- these aren't classes, they're
method calls. I looked at http://polygoncell.blogspot.com/2008/07/as-many-people-already-met-there-are.html
and all they did was replace the if block with switch. That doesn't
really eliminate the conditional now does it? I also read somewhere
else that I could use a map. The dilemma is my conditional calls
methods, not make assignments... so something like this really doesn't
work:

HashMap commandMap = new HashMap();
commandMap.put(1, method(1));
commandMap.put(2, method(2));
commandMap.put(3, method(3));
commandMap.put(4, method(4));

So while I'm NOT asking the forum to do my work for me, I am an
applied learner... and given a couple of the sources I've cited in my
post, I don't quite get getting rid of this conditional logic yet.
What is the best way to get rid of this smell?

Thanks!
 
J

Joshua Cranmer

Adam said:
I looked in Fowler's "Refactoring"... but replace conditional with
polymorphism doesn't seem to apply -- these aren't classes, they're
method calls.

It's not hard to turn method calls into classes.

public class ReducedIf {
private interface MethodFoo {
void doStuff();
}
private MethodFoo[] methods = new MethodFoo[
new MethodFoo() {
public void doStuff() {
// method here
}}, new MethodFoo() {
public void doStuff() {
}}];
}

Anonymous inner classes--or perhaps not so anonymous--can do the job of
calling methods. How to actually get an instance of one is more nuanced
and requires more particulars.

One option might be to make the number you're switching on into an enum,
and then putting the methods into an EnumMap. HashMaps or arrays are
other possibilities. But without more specifics, that's really all I can
say.
 
M

Mark Space

Joshua said:
It's not hard to turn method calls into classes.

public class ReducedIf {
private interface MethodFoo {
void doStuff();
}


or consider Runnable or Callable instead of a custom class like
"ReducedIf". The former two do have advantages, although making your
own specific type is not to be discounted out of hand.

Map<Integer, Runnable> ifMap = ....
int i ....

Runnable run = ifMap.get( i );
new Thread( run ).start(); // multi-threading for "free"
 
L

Lew

Adam said:
I'm having a hard time with implementing the notion of getting rid of
some "if then else" hell.

Given the following code sample:

if (i = 1)
{
method1(i);
}
else if (i = 2)
{
method2(i);
}
else if (i = 3)
{
method3(i);
}
else (i = 4)
{
method4(i);
}

I looked in Fowler's "Refactoring"... but replace conditional with
polymorphism doesn't seem to apply -- these aren't classes, they're

You could use polymorphism if you refactor the methods to be in different
implementations of a common type. More on that in a moment.
method calls. I looked at http://polygoncell.blogspot.com/2008/07/as-many-people-already-met-there-are.html
and all they did was replace the if block with switch. That doesn't

Nothing wrong with a switch, other than that it almost always masks a use case
for polymorphism.
really eliminate the conditional now does it? I also read somewhere

Nothing really eliminates the conditional, now does it?
else that I could use a map. The dilemma is my conditional calls
methods, not make assignments... so something like this really doesn't
work:

HashMap commandMap = new HashMap();
commandMap.put(1, method(1));
commandMap.put(2, method(2));
commandMap.put(3, method(3));
commandMap.put(4, method(4));

You need a functor, that is, a type that wraps a function. (All those guys
who favor closures are going nuts right now.)
So while I'm NOT asking the forum to do my work for me, I am an
applied learner... and given a couple of the sources I've cited in my
post, I don't quite get getting rid of this conditional logic yet.
What is the best way to get rid of this smell?

In the first place, stop calling it a "smell". You cannot get rid of the
conditional, because it's inherent to the logic. Your prejudice will undo you.

That said, I'd do it something like this, using polymorphism (each type to its
own source file, which I have not tried or compiled myself yet), without a lot
of error checking, ignoring exceptions, etc.:

public interface Command
{
public void command( int arg );
}

public class CommandA implements Command
{
@Override // use if at least Java 6
public void command( int arg )
{
System.out.println( "A arg = "+ arg ); // example only
}
}

public class CommandB implements Command
{
@Override
public void command( int arg )
{
System.out.println( "B arg = "+ arg );
}
}

public class CommandC implements Command
{
@Override
public void command( int arg )
{
System.out.println( "C arg = "+ arg );
}
}

public class CommandD implements Command
{
@Override
public void command( int arg )
{
System.out.println( "D arg = "+ arg );
}
}

public class RefactoredExample
{
private final Map <Integer, Command> commands;

/** Constructor. */
public RefactoredExample()
{
Map <Integer, Command> cmds = new HashMap <Integer, Command> ();
cmds.put( 1, new CommandA() );
cmds.put( 2, new CommandB() );
cmds.put( 3, new CommandC() );
cmds.put( 4, new CommandD() );
commands = Collections.unmodifiableMap( cmds );
}

public void doCommand( int chooser, int arg )
{
Command cmd = commands.get( chooser );
if ( cmd != null )
{
cmd.command( arg );
}
}
}

public class Client
{
public static void main( String args [] )
{
RefactoredExample eg = new RefactoredExample();
int chx = Integer.parseInt( args [0] );
int arg = Integer.parseInt( args [1] );
eg.doCommand( chx, arg );
}
}

A clever variation on this puts Class <? extends Command> objects as the
values in the map and instantiates the target object upon retrieval. There
are use cases for that.
 
T

Tom Anderson

I'm having a hard time with implementing the notion of getting rid of
some "if then else" hell.

Given the following code sample:

if (i = 1)
{
method1(i);
}
else if (i = 2)
{
method2(i);
}
else if (i = 3)
{
method3(i);
}
else (i = 4)
{
method4(i);
}

I looked in Fowler's "Refactoring"... but replace conditional with
polymorphism doesn't seem to apply -- these aren't classes, they're
method calls.

You may need to look deeper. Where does i come from? Does it come from a
class hierarchy to which the methods could be attached polymorphically (or
via a visitor)? Tell us more about this side of the problem.

If not ...
I looked at http://polygoncell.blogspot.com/2008/07/as-many-people-already-met-there-are.html
and all they did was replace the if block with switch. That doesn't
really eliminate the conditional now does it?

.... suck it up and use the switch. If your situation really is that you
need to call different methods according to the value of some integer,
then a switch is absolutely the right construct to use.

tom
 
A

Adam Sandler

Sorry for the late reply... been unable to get to a computer. At any
rate, thanks for all the replies -- lots of good ideas for me to
explore!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,607
Members
45,240
Latest member
pashute

Latest Threads

Top