2012-04-16 159 views
29

我已经阅读了很多关于代码重构和避免if else语句的主题。 其实,我有一个课,我使用了很多if - else条件。如何避免很多其他条件

更多细节:我使用的是拉解析器和我SOAP响应的每一行,我会检查是否有标签我感兴趣的,如果没有,检查另一个标记等:

if(eventType == XmlPullParser.START_TAG) { 
      soapResponse= xpp.getName().toString(); 

      if (soapResponse.equals("EditorialOffice")){ 
       eventType = xpp.next(); 
       if (xpp.getText()!=null){ 
       editorialOffice += xpp.getText(); 
       } 
      } 
      else if (soapResponse.equals("EditorialBoard")){ 
       eventType = xpp.next(); 
       if (xpp.getText()!=null){ 
       editorialBoard += xpp.getText(); 
       } 
      } 
      else if (soapResponse.equals("AdvisoryBoard")){ 
       eventType = xpp.next(); 
       if (xpp.getText()!=null){ 
       advisoryBoard += xpp.getText(); 
       } 
      } 
     } 
     eventType = xpp.next(); 
    } 

现在,我想用其他的,而不是那些如果其他条件,但我不知道是什么。

你可以给我一个例子或一个很好的教程页吗?

谢谢。

+0

你可以维护字符串到程序中其他地方的枚举映射,从映射中抽出与返回字符串关联的枚举(如果字符串不在映射中,则使用默认的'NO_MATCH')并写入在枚举上切换语句。它可能会使代码更清晰,但会增加额外的间接层。你必须判断这是否值得。 – 2012-04-16 14:24:42

+2

检查: http://stackoverflow.com/questions/519422/what-is-the-best-way-to-replace-or-substitute-if-else-if-else-trees-在程序中 希望对您有所帮助 – 2012-04-16 14:27:54

+0

请注意,出于性能方面的原因,您应该使用StringBuilder而不是+ =来连接字符串。 – 2012-04-19 14:40:19

回答

18

在这个特定的情况下,由于码是所有3的情况下,除了字符串基本上相同被附加到,我将不得不为每个字符串的映射条目正在构建:

Map<String,String> map = new HashMap<String,String>(); 
map.put("EditorialOffice",""); 
map.put("EditorialBoard",""); 
map.put("AdvisoryBoard",""); 
// could make constants for above Strings, or even an enum 

,然后将您的代码更改为以下内容

if(eventType == XmlPullParser.START_TAG) { 
    soapResponse= xpp.getName().toString(); 
    String current = map.get(soapResponse); 
    if (current != null) { 
     eventType = xpp.next(); 
     if (xpp.getText()!=null){ 
      map.put(soapResponse, current += xpp.getText()); 
     } 
    } 
    eventType = xpp.next(); 
} 

否“if ... then ... else”。甚至没有为战略模式增加多个类的复杂性等。地图是你的朋友。在某些情况下策略很棒,但是这个策略非常简单,无需解决。

5

除了zzzzzzz(etc。)的评论......请记住,您正在使用XmlPullParser,它使您可以编写您喜欢的代码。你可以注册一些回调来分割你的代码并使其更好,但如果可能的话,只需使用SimpleXML库或类似的代码。

此外,你可以重构你的代码,使其更具可读性和更少的冗长。例如,为什么你在每个if语句中调用xpp.next()?为什么不只在外面调用它:

if(eventType == XmlPullParser.START_TAG) { 
    soapResponse= xpp.getName().toString(); 
    if (soapResponse.equals("EditorialOffice") && xpp.getText()!=null){ 
     editorialOffice += xpp.getText(); 
    } 
    else if (soapResponse.equals("EditorialBoard") && xpp.getText()!=null){ 
     editorialBoard += xpp.getText(); 
    } 
    else if (soapResponse.equals("AdvisoryBoard") && xpp.getText()!=null){ 
     advisoryBoard += xpp.getText(); 
    } 
} 
eventType = xpp.next(); 
+0

谢谢@Cristian,事实上,我正在从服务器获取xml响应,我不知道我是否可以使用别的东西,这与XML pull解析器非常相似。我在每条语句上调用xpp.next(),而当找到我要查找的开始标记时,则在下一行中,我会找到需要的变量,并将其放入我的局部变量中。 – 2012-04-16 14:24:58

+0

['XmlPullParser.getName()'](http://www.xmlpull.org/v1/doc/api/org/xmlpull/v1/XmlPullParser.html#getName())返回'String',所以有不需要调用'.toString()'。 – 2012-04-16 14:41:22

+0

@Ana只是看看SimpleXML库;它会让你的生活更轻松,更快乐。 – Cristian 2012-04-16 15:12:48

6

在Java 7中,您可以在字符串上进行切换。你可以使用它,如果你可以使用它;-)

+12

+1“如果你可以使用它,你可以使用它。如果我们有鸡蛋,我们可以有火腿和鸡蛋,如果我们有火腿。 – 2012-04-16 15:03:05

33

试着看看战略模式。

  • 做一个接口类用于处理响应(IMyResponse)
    • 使用此IMyResponse创建AdvisoryBoardResponse,EditorialBoardResponse类
  • 创建与soapresponse值为键,你的战略,作为一个词典值
  • 然后,您可以使用IMyResponse类的方法从字典中获取它

小例子:

// Interface 
public interface IResponseHandler { 
    public void handleResponse(XmlPullParser xxp); 

} 

// Concrete class for EditorialOffice response 
private class EditorialOfficeHandler implements IResponseHandler { 
    public void handleResponse(XmlPullParser xxp) { 
     // Do something to handle Editorial Office response 
    } 
} 

// Concrete class for EditorialBoard response 
private class EditorialBoardHandler implements IResponseHandler { 
    public void handleResponse(XmlPullParser xxp) { 
     // Do something to handle Editorial Board response 
    } 
} 

在您需要创建的处理程序的地方:

Map<String, IResponseHandler> strategyHandlers = new HashMap<String,IResponseHandler>(); 
strategyHandlers.put("EditorialOffice", new EditorialOfficeHandler()); 
strategyHandlers.put("EditorialBoard", new EditorialBoardHandler()); 

如果您收到响应:

IResponseHandler responseHandler = strategyHandlers.get(soapResponse); 
responseHandler.handleResponse(xxp); 
+0

谢谢@hwcverwe,这在我看来是一个好主意。你能否给我一个更精确的例子来说明如何做到这一点?非常感谢。 – 2012-04-16 14:27:31

+2

也许这适用于更复杂的多条件决策。但是这对于这种特殊情况来说不觉得太重了吗?哎呀,我甚至更喜欢“如果,那么,如果”通过这个解决方案,在这种特殊情况下(尽管存在其他更简单的解决方案)。 – 2012-04-16 14:47:01

+0

@KevinWelker这有点复杂,但如果你考虑可维护性,将来会更容易。与其他响应处理程序一起扩展策略非常容易。而且它更易读if-elseif-else语句 – hwcverwe 2012-04-16 14:59:28

3

你可以创建一个对ResponseHandler接口三个实现,一个用于if/else构造的每个分支。

然后有一个映射将不同的soapResponses映射到一个处理程序,或者是一个包含所有处理程序的列表(如果它可以处理该soapResponse)。

您还应该能够将一些样板代码移动到响应处理程序类的常见可能抽象实现。

由于经常有这样的许多变化。通过利用代码重复一个实际上只需要一个实现:

class ResponseHandler{ 
    String stringToBuild = "" // or what ever you need 
    private final String matchString 

    ResponseHandler(String aMatchString){ 
     matchString = aMatchString 
    } 
    void handle(XppsType xpp){ 
     if (xpp.getName().toString().equals(matchString){ 
      eventType = xpp.next(); 
      if (xpp.getText()!=null){ 
       editorialOffice += xpp.getText(); 
      } 
     } 
    } 
} 

你的代码变得

List<ResponseHandler> handlers = Arrays.asList(
    new ResponseHandler("EditorialOffice"), 
    new ResponseHandler("EditorialBoard"), 
    new ResponseHandler("AdvisoryBoard")); 
if(eventType == XmlPullParser.START_TAG) { 
    for(ResponseHandler h : handlers) 
     h.handle(xpp); 
} 
+0

谢谢@Jean Sxhauder,请给我一个如何使用它的例子吗? – 2012-04-16 14:43:00

+0

增加了一个示例实现 – 2012-04-16 14:57:15

3

广大疑问,这是一个并没有真正的答案。 (我不使用肥皂经常)

这里只是一些想法基于代码:

首先,你可以狮重复的代码

if (soapResponse.equals("EditorialOffice") 
||soapResponse.equals("EditorialBoard") 
||soapResponse.equals("AdvisoryBoard")){ 

你可以做的另一个好处是发挥周围的开关staments像:

switch(soapResponse){ 
case "EditorialOffice": 
case "EditorialBoard": 
case "AdvisoryBoard": 
eventType = xpp.next(); 
       if (xpp.getText()!=null){ 
       advisoryBoard += xpp.getText(); 
       } 
break; 

你也应该考虑打破你考到小功能:

public bool interestingTag(string s){ 
return (soapResponse.equals("EditorialOffice") 
    ||soapResponse.equals("EditorialBoard") 
    ||soapResponse.equals("AdvisoryBoard")); 
} 

    public processData(xpp){ 
    eventType = xpp.next(); 
        if (xpp.getText()!=null){ 
        editorialBoard += xpp.getText(); 
        } 
    ....} 

这样你可以处理所有的答案在一个while循环,你超长的if else变成5〜10线功能

但正如我说,有做同样的事情这么多的好方法

4

你还没有提到,如果你可以或使用Java 7.从那个Java版本,你可以使用Strings in switch statements

除此之外,封装逻辑每种情况下是一个好主意,例如:

Map<String, Department> strategyMap = new HashMap<String, Department>(); 
strategyMap.put("EditorialOffice", new EditorialOfficeDepartment()); 
strategyMap.put("EditorialBoard", new EditorialBoardDepartment()); 
strategyMap.put("AdvisoryBoard", new AdvisoryBoardDepartment()); 

然后,你可以简单地从地图上选择了正确的策略,并使用它:

String soapResponse = xpp.getName(); 
Department department = strategyMap.get(soapResponse); 
department.addText(xpp.getText()); 

Department当然是在接口...

+0

经过所有工作中断后,我终于提交了答案,但@ hwcverwe同时已经提交了几乎相同的答案(参见上文)。 – 2012-04-16 15:29:22

0

你可以定义一个枚举如下:

public enum SoapResponseType { 
    EditorialOffice(1, "description here") { 
     public void handle(XmlPullParser xpp) { 
      //do something you want here 
      return null; 
     } 
    }, 
    EditorialBoard(2, "description here") { 
     public void handle(XmlPullParser xpp) { 
      //do something you want here 
      return null; 
     } 
    }, 
    AdvisoryBoard(3, "description here") { 
     public void handle(XmlPullParser xpp) { 
      //do something you want here 
      return null; 
     } 
    }; 

    public static SoapResponseType nameOf(String name) { 
     for (SoapResponseType type : values()) { 
      if (type.getName().equalsIgnoreCase(name)) { 
       return type; 
      } 
     } 
     return null; 
    } 

    public void handle(XmlPullParser xpp) { 
     return null; 
    } 
} 

使用上述枚举这样的:

SoapResponseType type = SoapResponseType.nameOf("input string"); 
if (type != null) { 
    type.handle(xpp); 
} 

它是干净的代码,是不是!