53

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

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

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

现在,我想使用其他东西,而不是那些 if else 条件,但我不知道是什么。

你能给我一个例子吗?

4

8 回答 8

58

尝试查看策略模式。

  • 制作一个用于处理响应的接口类(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);
于 2012-04-16T14:22:13.953 回答
34

在这种特殊情况下,由于除了附加的字符串之外,所有 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 && xpp.getText()!=null) {
        map.put( soapResponse, current += xpp.getText());
    }
    eventType = xpp.next();
}

没有“如果……那么……否则”。甚至不会增加策略模式等多个类的复杂性。地图是您的朋友。策略在某些情况下很棒,但这个策略很简单,不用也可以解决。

于 2012-04-16T14:33:05.357 回答
10

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

于 2012-04-16T14:21:30.107 回答
6

除了 zzzzzzz(etc.) 的评论...请记住,您使用的是 XmlPullParser,这会让您编写像您所拥有的那样丑陋的代码。您可以注册一些回调来拆分您的代码并使其“更好”,但如果可能,只需使用 SimpleXML 库或类似库。

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

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();
于 2012-04-16T14:20:38.370 回答
6

您可以创建一个具有三个实现的 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);
}
于 2012-04-16T14:26:05.037 回答
5

这是一个广泛的问题,没有真正的答案。(而且我不经常使用肥皂)

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

首先你可以对重复的代码进行分组

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

您可以做的另一件好事是使用 switch 语句,例如:

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 循环中处理你所有的答案,如果 else 变成一个 5~10 行的函数,你就会超长

但正如我所说,有很多好方法可以做同样的事情

于 2012-04-16T14:28:52.740 回答
5

您没有提到是否可以或确实使用 Java 7。从该 Java 版本开始,您可以在 switch 语句中使用字符串

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

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当然是在界面...

于 2012-04-16T15:26:22.757 回答
4

您可以定义如下枚举:

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

这是干净的代码,不是吗!

于 2017-07-25T14:08:07.193 回答