As noted in a comment, there are ways to use java's reflection capabilities. See this question for how to do that. That said, reflection is pretty bad style in java and should only be used if you really have no other option. Java's really big on OO-style programming and static type checking and using reflection is skimping on both of those focuses. In doing so you'll likely make your code just as complicated and way harder to debug.
Without reflection, there's not much better you can do if the code block in question happens exactly once. You'd have to implement the logic somewhere, probably involving the same if-else/switch block. However, if you find yourself copy-pasting that same if-elseif-elseif-elseif.... block in multiple places, you can do a bit better.
If type
is an enum, you can move the logic to the enum itself, which is really nice from an OO standpoint. Consider the following:
public enum Direction {
NORTH,
SOUTH,
EAST,
WEST
}
public class Foo {
public void bar(Direction d) {
//At some point we want some logic to depend on the vector dx,dy form of d
int dx = 0;
int dy = 0;
switch(d) {
case NORTH:
dy = -1;
break;
case SOUTH:
dy = 1;
break;
case EAST:
dx = 1;
break;
case WEST:
dx = -1;
break;
}
//Use the values in dx, dy
}
}
It's clearly a bad idea to copy-paste this block around your project. If you ever add a new direction, you'd have to return to every such block to add the correct addition. From an OO standpoint, the dx, dy fields are truly part of the enum value, and should be a part of it to begin with. Thus we can change the above to the following:
public enum Direction {
NORTH,
SOUTH,
EAST,
WEST;
public int getDX() {
switch(this) {
case WEST: return -1;
case EAST: return 1;
default: return 0;
}
}
public int getDY() {
switch(this) {
case NORTH: return -1;
case SOUTH: return 1;
default: return 0;
}
}
}
Or, (IMO) even better, represent them as a field
public enum Direction {
NORTH(0,-1),
SOUTH(0,1),
EAST(1,0),
WEST(-1,0);
private int dx;
private int dy;
private Direction(int dx, int dy) {
this.dx = dx;
this.dy = dy;
}
public int getDX() {
return dx;
}
public int getDY() {
return dy;
}
}
From there we can simply use these methods directly in Foo.bar()
and don't need any logic:
public class Foo {
public void bar(Direction d) {
//can directly use d.getDX() and d.getDY()
}
}
Your question about function calling is the same, if one level removed. We can either add the switch straight to the enum:
public enum Type {
VALUE_ONE, VALUE_TWO, ...
public void callFunc() {
switch(this) {
case VALUE_ONE:
callFunctionOne();
return;
case VALUE_TWO:
callFunctionTwo();
return;
//....
}
}
}
And then just use it by directly referencing that function:
Type t = //....
t.callFunc();
You could even use some java-8 stuff to represent the function-to-call as a field
@FunctionalInterface
public interface Unit {
public void apply();
}
public enum Type {
VALUE_ONE(Foo::baz),
VALUE_TWO(Foo::baz2),
//...
private Unit funcToCall;
private Type(Unit u) {
this.funcToCall = u;
}
public void callFunc() {
funcToCall.apply();
}
}
If type
is not an enum, you can use some (but not all) of the above options. You can still lump your switch logic into a helper method/class and pass control over to it instead of copy/pasting. The more that type
is supposed to represent something, and the more you find yourself wanting to switch
over it, the more likely an enum is the correct choice.