2012-03-26 12 views
2

辞書ウェブサイトからウェブページを解析する単語定義フェッチャーを作成しました。 すべてのWebページがまったく同じHTML構造を持っているわけではないので、大部分のケースをサポートするためにいくつかの解析メソッドを実装する必要がありました。反復的なフォールバックメカニズムを実装するためのデザインパターン

以下は私がこれまで行ってきたことですが、これはかなり醜いコードです。私はNを実装できるように、反復フォールバックメカニズムのいくつかの種類をコーディングするクリーンな方法だろうと思います何

は、メソッドの構文解析注文(パース失敗は次の構文解析をトリガしなければならない、(より適切な用語があるかもしれません) IOExceptionのような例外はプロセスを破壊するはずです)。

public String[] getDefinition(String word) { 
    String[] returnValue = { "", "" }; 
    returnValue[0] = word; 
    Document doc = null; 
    try { 
     String finalUrl = String.format(_baseUrl, word); 
     Connection con = Jsoup.connect(finalUrl).userAgent("Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17"); 
     doc = con.get(); 
     // *** Case 1 (parsing method that works for 80% of the words) *** 
     String basicFormOfWord = doc.select("DIV.luna-Ent H2.me").first().text().replace("·", ""); 
     String firstPartOfSpeech = doc.select("DIV.luna-Ent SPAN.pg").first().text(); 
     String firstDef = doc.select("DIV.luna-Ent DIV.luna-Ent").first().text(); 

     returnValue[1] = "<b>" + firstPartOfSpeech + "</b><br/>" + firstDef; 
     returnValue[0] = basicFormOfWord; 
    } catch (NullPointerException e) { 
     try { 
      // *** Case 2 (Alternate parsing method - for poorer results) *** 
      String basicFormOfWord = doc.select("DIV.results_content p").first().text().replace("·", ""); 
      String firstDef = doc.select("DIV.results_content").first().text().replace(basicFormOfWord, ""); 

      returnValue[1] = firstDef; 
      returnValue[0] = basicFormOfWord; 
     } catch (Exception e2) { 
      e2.printStackTrace(); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return returnValue; 
} 
+1

のように、コードを修正し、あなたがのチェーンを考慮することができます責任[パターン](http://www.javacamp.org/designPattern/chains.html) – Renard

答えて

1

すでに説明したように、責任の連鎖は適切な候補です。 Johnの答えOrlは、UrlParserが次のパーサーへの要求を処理するかどうかを積極的に決定しないため、適切な意味での責任の連鎖はありません。 ここでの私の些細なショットです:

public class ParserChain { 
    private ArrayList<UrlParser> chain = new ArrayList<UrlParser>(); 
    private int index = 0; 
    public void add(UrlParser parser) { 
     chain.add(parser); 
    } 
    public String[] parse(Document doc) throws IOException { 
     if (index = chain.size()){ 
      return null; 
     } 
     return chain.get(index++).parse(doc); 
    } 
} 

public interface UrlParser { 
    public String[] parse(Document doc, ParserChain chain) throws IOException; 
} 

public abstract class AbstractUrlParser implements UrlParser { 
    @Override 
    public String[] parse(Document doc, ParserChain chain) throws IOException { 
     try { 
      return this.doParse(doc); 
     } catch (ParseException pe) { 
      return chain.parse(doc); 
     } 
    } 
    protected abstract String[] doParse(Document doc) throws ParseException, IOException; 
} 

注目すべき事柄:

  • このコードは、いくつかのパーサが停止するまで、ParserChain番号の解析とそれが入ったすべてのパーサーのUrlParser番号の解析のための1つのスタックフレームを保持しますが、責任の連鎖巨大なチェーンを持っている場合、スタックオーバーフローで実行することができます(適切な方法)
  • AbstractUrlParserを拡張しないUrlParserは、引数Stringを変更し、次のチェーンを委任するか、チェーン内の次のチェーンを委任してから、結果。
  • 編集

ParserChainはスレッドセーフではありません(私は、これはChain of Responsibilityパターンに固有なものだと思います):セバスチャンさんのコメント

+0

ありがとう、私はあなたの提案に固執すると思います。私は、最後のreturn文は 'return chain.parse(doc);であるべきだと思います。 –

2

Chain-of-Responsibilityのようなサウンドです。私は、次のを持っているでしょう:

public interface UrlParser(){ 
    public Optional<String[]> getDefinition(String word) throws IOException; 
} 

public class Chain{ 
    private List<UrlParser> list; 

    @Nullable 
    public String[] getDefinition(String word) throws IOException{ 
     for (UrlParser parser : list){ 
      Optional<String[]> result = parser.getDefinition(word); 
      if (result.isPresent()){ 
       return result.get(); 
      } 
     } 
     return null; 
    } 
} 

私はここにグアバのOptionalを使用していますが、あなたが同様のインターフェイスから@Nullableを返すことができます。次に、必要な各URLパーサーのクラスを定義し、それらに挿入します。Chain

関連する問題