2011-04-15 38 views
2

我有下面的代码段(缩短为例子):重构模式匹配的序列

while (reader.ready()) { 
    String line = reader.readLine(); 

    Matcher responseCodeMatcher = responseCodePattern.matcher(line); 
    if (responseCodeMatcher.matches()) { 
     responseCode = Integer.parseInt(responseCodeMatcher.group(1)); 
     continue; 
    } 

    Matcher cacheControlMatcher = cacheControlPattern.matcher(line); 
    if (cacheControlMatcher.matches()) { 
     cacheControl = CacheControl.parseString(responseCodeMatcher.group(1)); 
     continue; 
    } 

     ... 

} 

的模式是类的所有的静态最终成员。 所以我有一堆模式,我想找出每一行,如果它匹配其中之一,如果是这样 - 做一些事情(从模式到模式)。你能想出一种很好地重构这种方式吗?也许是我过去的一系列模式(然后我怎么知道如果匹配,该怎么做?)或其他一些想法。

+2

仅供参考,'while(reader.ready())'不正确。 'ready()'方法告诉你Reader是否可以在不阻塞的情况下读取更多*,而不是如果有更多的文本被读取。一行一行的阅读习惯是'while((line = reader.readLine())!= null)'。 – 2011-04-15 15:02:51

回答

2

我以如下方式结束了重构。我创建了一个类HttpPatterns

package cs236369.proxy.types; 

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

public enum HttpPatterns { 
    RESPONSE_CODE("^HTTP/1\\.1 (\\d+) .*$"), 
    CACHE_CONTROL("^Cache-Control: (\\w+)$"), 
    HOST("^Host: (\\w+)$"), 
    REQUEST_HEADER("(GET|POST) ([^\\s]+) ([^\\s]+)$"), 
    ACCEPT_ENCODING("^Accept-Encoding: .*$"), 
    CONTENT_ENCODING("^Content-Encoding: ([^\\s]+)$"); 

    private final Pattern pattern; 

    HttpPatterns(String regex) { 
     pattern = Pattern.compile(regex); 
    } 

    public boolean matches(String expression) { 
     return pattern.matcher(expression).matches(); 
    } 

    public Object process(String expression) { 
     Matcher matcher = pattern.matcher(expression); 
     if (!matcher.matches()) { 
      throw new RuntimeException("Called `process`, but the expression doesn't match. Call `matches` first."); 
     } 

     if (this == RESPONSE_CODE) { 
      return Integer.parseInt(matcher.group(1)); 
     } else if (this == CACHE_CONTROL) { 
      return CacheControl.parseString(matcher.group(1)); 
     } else if (this == HOST) { 
      return matcher.group(1); 
     } else if (this == REQUEST_HEADER) { 
      return new RequestHeader(RequestType.parseString(matcher.group(1)), matcher.group(2), matcher.group(3)); 
     } else if (this == CONTENT_ENCODING) { 
      return ContentEncoding.parseString(matcher.group(1)); 
     } else { //never happens 
      return null; 
     } 
    } 


} 

我用它像这样:

String line; 
      while ((line = reader.readLine()) != null) { 

       if (HttpPatterns.CACHE_CONTROL.matches(line)) { 
        cacheControl = (CacheControl) HttpPatterns.RESPONSE_CODE.process(line); 
       } else if (HttpPatterns.REQUEST_HEADER.matches(line)) { 
        requestHeader = (RequestHeader) HttpPatterns.REQUEST_HEADER.process(line); 
       } else if (HttpPatterns.HOST.matches(line)) { 
        requestHost = (String) HttpPatterns.HOST.process(line); 
       } else if (HttpPatterns.ACCEPT_ENCODING.matches(line)) { 
        continue; 
       } else if (line.isEmpty()) { 
        break; 
       } 
       fullRequest += "\r\n" + line; 
      } 

我不喜欢,我要投的一切,我得到的,但是这是我迄今为止所发现的最佳解决方案。

2

因为到目前为止没有人回答,我会,虽然我不知道Java。
在C#中我会创建一个元组列表。元组的项目1是要检查的模式,项目2是一个匿名方法,它包含要执行的特定于模式的代码。在C#中,它会是这个样子:

var patterns = new List<Tuple<Pattern, Action<Matcher>>>(); 
patterns.Add(Tuple.Create(responseCodePattern, matcher => 
    { 
     responseCode = Integer.parseInt(matcher.group(1)); 
    })); 

patterns.Add(Tuple.Create(cacheControlPattern, matcher => 
    { 
     cacheControl = CacheControl.parseString(matcher.group(1)); 
    })); 

while (reader.ready()) { 
    String line = reader.readLine(); 
    foreach(var tuple in patterns) 
    { 
     Matcher matcher = tuple.Item1.matcher(line); 
     if(matcher.matches()) 
     { 
      tuple.Item2(matcher); 
      break; 
     } 
    } 
} 

我不知道,如果这使得任何意义,一个Java的家伙,尤其是与lambda语法......请问,如果不是:-)

+0

在Java中,你需要编写一个接口,如公共接口UseMatcher {match(Matcher matcher); }然后你需要为每件事写一个匿名的内部类。那么你需要跳过一些箍环,因为你只能访问内部类中的最终变量。你可能最终会声明像int [] responseCode = new int [1]和每个地方都使用responseCode [0]。总之这种方法在Java中有点痛苦:) – 2011-04-15 14:13:11

+0

@Jeff:真是可惜... – 2011-04-15 14:15:36

0

好的,这里是我的简短答案:这不是一个语言问题,迄今为止的答案和评论都是非常热门的。所有的语言,不管如何reprobate,包括类型。这是一个关于如何检测这些类型然后执行适当的相应操作的问题。答案是来自四本书帮派的一些模式。

首先,对于解析部分,我建议您将其视为中介。这些行为应该对模式或文件一无所知,同样,行为的知识不应该被注入到触发的上下文中。你可以称它为解析器,探测器等等,但是这个类的核心将会是这个模式映射到适当的动作。

在动作方面,使用的模式当然是Command模式。使用命令时有很多可能性。如果你不需要上下文,那么这个命令非常简单,它只是一个执行方法。如果你需要传递一些将要改变的上下文,你可以模拟这些命令或者随时创建新的命令然后调用它们。