Reputation: 156
What can be best design pattern for handling condition based method calls? Conditions are based on string comparison. I know basic if-else-if or switch can solve it but still looking for other solution.
Example:
User inputs the strings foo1
, foo2
and foo3
in sequential order. Now the program calls a method on the basis of these inputs i.e.:
if (input.equals("foo1"))
fun1();
else if(input.equals("foo2"))
fun2();
and so on.
Also, the functionality of fun1()
and fun2()
are entirely independent of each other.
Upvotes: 1
Views: 4014
Reputation: 1133
You can simplify it by using Runnables instead of a factory:
public class Router {
private Map<String, Class> map;
public Router() {
this.map = new HashMap<>();
map.put("foo1", new Runnable(){
run(){
fun1();
}
});
map.put("foo2", new Runnable(){
run(){
fun2();
}
});
}
public void doRoot(String command) throws IllegalArgumentException {
Runnable r = map.get(command);
if(r == null){
throw new IllegalArgumentException("invalid command: " + command);
}
r.run();
}
fun1(){}
fun2(){}
}
Upvotes: 0
Reputation: 3749
It depends. In your case, there isn't one. But usually you would solve this by some form of polymorphism or Template Method pattern. But your data model doesn't seem to have been designed in such a way, so you're pretty much screwed, and you'll have to make an ugly nested IF structure. Alternatively you can refactor it slightly and use a Template Method Pattern. In this scenario you could use a Factory method pattern to create different templates based on the String, each of these templates would thn have a different TemplateMethod()
which would be invoked. This allows you to treat all object equally, yet have one part (the template method) act independently.
For a more in-depth explanation, see: http://en.wikipedia.org/wiki/Template_method_pattern
Edit: Added example, of less shitty Factory method.
TemplateFactory.java
public class TemplateFactory {
private Map<String, Class> map;
public TemplateFactory() {
this.map = new TreeMap<>();
map.put("Template 1", Template1.class);
map.put("Template 2", Template2.class);
}
public BaseTemplate createBaseTemplate(String comparison)
{
if (!map.containsKey(comparison))
{
return null;
}
try {
return (BaseTemplate) map.get(comparison).getConstructor().newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
TemplateFactory tf = new TemplateFactory();
BaseTemplate t1 = tf.createBaseTemplate("Template 1");
BaseTemplate t2 = tf.createBaseTemplate("Template 2");
System.out.println(t1.templateMethod(""));
System.out.println(t2.templateMethod(""));
}
}
BaseTemplate.java
public abstract class BaseTemplate {
public String doSomething()
{
// whatever
return "Hello";
}
public int anotherRealMethod(String data)
{
//also whatever
return 0;
}
public abstract String templateMethod(String data);
}
Template1.java
public class Template1 extends BaseTemplate {
@Override
public String templateMethod(String data) {
return "Template 1";
}
}
Template 2.java
public class Template1 extends BaseTemplate {
@Override
public String templateMethod(String data) {
return "Template 2";
}
}
Upvotes: 1
Reputation: 11284
In your case, I will consider a combination of enum
and switch case
. The reason we should not use string for this is:
If you use a misspelled string to called your function (getFunction("foO")
instead of getFuntion("foo")
) , you don't have any idea how to debug it, the compiler will not tell you anything.
And If you mistakenly used two identical String to refer to two different methods, you could not detect it also.
You cannot iterate through all of your string , enum
has a values()
method for that.
So my advice is use an enum
public enum Function{
foo1,
foo2;
}
Upvotes: 0