Reputation: 12321
I have a list and I have functions.
I want to iterate the list and call the function that matches the lists element. How can I do that in a more elegant way than comparing the name in a if or switch?
class C
{
String [] lst = {"foo", "bar", "zoo"};
void foo () { /* ... */ }
void bar () { /* ... */ }
void NotSoElegant ()
{
for (String s : lst)
{
if (s.equals ("foo") == true)
{ foo (); }
if (s.equals ("bar") == true)
{ bar (); }
}
}
}
Upvotes: 2
Views: 579
Reputation: 77177
Use the Replace Conditional with Polymorphism refactoring along with lambdas/method references. Assuming that your methods don't take parameters and don't return anything, they match the Runnable
interface:
class MoreElegant {
static final Map<String, Runnable> COMMANDS = Map.of(
"foo", MoreElegant::foo,
"bar", MoreElegant::bar,
"baz", () -> { doSomethingElse(); }
);
void execute(List<String> commands) {
commands.forEach(c ->
COMMANDS
.getOrDefault(c, () -> throw new IllegalArgumentException("no command " + c))
.run()
);
}
}
Upvotes: 3
Reputation: 13571
I strongly advise against to use reflection in such case - it's obviously code smell, it's breaching the security of your code and may cause many, many issues and drawbacks - just think what will happen if someone will put NotSoElegant
in the list.
Of course there are methods to fetch method by name so basically you could scan the class, get method by string, handle exceptions... Do not do this.
Basically there is nothing bad in having such set of ifs
however you can refactor this a little bit using switch
statement
for (String s : lst) {
switch(s) {
case "foo":
foo();
break;
case "bar":
bar();
break;
}
}
If you want to be more SOLID complain and do not break Open-Closed rule you should rather think about using some design patterns (like Strategy) but do not use reflection :)
Upvotes: 5