Pergunta

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.

Foi útil?

Solução

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";
    }
}

Outras dicas

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;
} 

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(){}

}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top