2014-05-02 143 views
-4

什麼是處理基於條件的方法調用的最佳設計模式?條件基於字符串比較。我知道基本的if-else-if或switch可以解決它,但仍然在尋找其他解決方案。處理基於條件的方法調用的最佳設計

實施例:

用戶輸入字符串foo1foo2和按順序foo3。現在該程序根據這些輸入調用方法,即:

if (input.equals("foo1")) 
    fun1(); 
else if(input.equals("foo2")) 
    fun2(); 

等等。

而且,fun1()fun2()的功能是完全相互獨立的。

+0

你能否提供更多細節? '條件是基於字符串比較'的?請舉例 –

+1

這個問題太廣泛了。根據需要,您可能會考慮使用有限狀態機或其他技術。 – user3159253

+0

只是想澄清,你爲什麼需要這樣做?方法名是否足夠?通過字符串引用方法對我來說是雙倍的工作。 –

回答

0

這取決於。在你的情況下,沒有一個。但通常你會通過某種形式的多態或模板方法模式來解決這個問題。但是你的數據模型似乎並沒有被設計成這樣,所以你幾乎搞砸了,你將不得不做一個醜陋的嵌套IF結構。或者,您可以稍微重構它並使用模板方法模式。在這種情況下,您可以使用Factory方法模式根據字符串創建不同的模板,這些模板中的每一個都會有不同的TemplateMethod(),這些模板將被調用。這允許您平等對待所有對象,但是隻有一個部分(模板方法)獨立行事。

對於更深入的說明,請參見:http://en.wikipedia.org/wiki/Template_method_pattern

編輯:添加例如,更少低劣工廠方法。

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

模板2.java

public class Template1 extends BaseTemplate { 
    @Override 
    public String templateMethod(String data) { 
     return "Template 2"; 
    } 
} 
+0

即使工廠模式使用醜陋的if-else-if結構(只是一個天真的例子http://www.tutorialspoint.com/design_pattern/factory_pattern.htm形狀工廠類)。現在想象幾百種不同的形狀(圓形,方形,五角形等),所以這個造型班看起來很可怕。我只是在尋找更好的方法。 – avenger

+0

不一定。這是一個很糟糕的例子。一個更好的例子是在你的工廠中保存一個Map ,然後查找你需要的類,並將它作爲IoC容器的依賴項,或者簡單地創建一個新的實例。 –

+0

@avenger我已經更新了我的答案,其中包括一個闡述我的答案的例子。理想情況下,您應該使用IoC容器(如Spring BeanFactory或Guice Injector)來創建和處理對象生命週期,而不是使用反射。但是設置這個問題有點超出了問題的範圍。 –

0

就你而言,我會考慮enumswitch case的組合。我們不應該使用字符串造成這種情況的原因是:

  • 如果使用拼錯字符串叫你的函數(的getFunction("foO")代替getFuntion("foo")),你沒有任何想法如何調試它,編譯器會沒有告訴你任何事情。

  • ,如果你錯誤地使用兩個相同的字符串,它指兩種不同的方法,你無法檢測它也。

  • 不能通過所有的字符串迭代,enum有一個values()方法。

所以我的建議是使用enum

public enum Function{ 
    foo1, 
    foo2; 
} 
0

可以使用,而不是一個工廠的Runnable簡化它:

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

}