Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

デザインパターンの使い方: Interpreter

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/12/02 14:00

 Interpreterパターンは、言語の文法をオブジェクトで表現し、そのオブジェクトを用いて言語の文を解釈するためのデザインパターンです。本稿では、単純なブール言語をサポートするインタープリタの作成を例に、Interpreterパターンを解説していきます。

目次

Interpreterパターンの例

 GoFの『オブジェクト指向における再利用のためのデザインパターン』では、Interpreterパターンは基本的にCompositeパターンと同じもので、その目的が違うだけだと紹介されています。Compositeパターンから結果として得られる階層構造が文法のようなものである場合、それはInterpreterパターンであると言えます。実際のところ、Compositeパターンのときに作成した例は、Interpreterパターンの実装例としても使えます。そういうわけで、本稿ではこれ以上の説明は必要なさそうです。

 しかし、ここで終わるわけにもいきません。というのは、開発者の皆さんにInterpreterパターンを理解してもらうのに役立つ、ちょうど良い例がほとんど紹介されていないからです。本稿の例は、完璧な例ではないかもしれませんが、「interpreter design pattern」と検索して見つけた例と比較すると、かなり分かりやすいのではないでしょうか。

 今回は、単純なブール言語をサポートするインタープリタの作成を目標にします。この言語は最終的に、動的な条件に基づいてフォルダ間で文書を移動させるための、簡単なコマンドセットの基礎となります。アプリケーションの例として「履歴書フィルタ」を考えてみます。例えば、次のようなコマンドがあるとしましょう。

move from incomingResumes to phoneScreen when
   contains fortran or smalltalk and olderThan 01/01/2006

 ここで、式の2行目、「contains」で始まる行に着目します。Interpreterパターンは、式から結果が1つだけ得られるようなものに最も適しているからです。

 今回の例では文書を扱うので、インタープリタの使い方を説明するために簡単な文書クラスが必要です。リスト1に、TextDocumentクラスの実装を示します。このクラスではcontainsメソッドをサポートし、作成日をカプセル化します。私はいつもテスト駆動開発をするようにしているので、TextDocumentクラスのテストも用意しました(リスト2)。

リスト1 Documentインターフェースとその実装クラス
// Document.java
public interface Document {
   public boolean contains(String... keywords);

   public java.util.Date getDate();
}

// TextDocument.java
import java.util.*;

public class TextDocument implements Document {
   private final String contents;
   private final Date date;

   public TextDocument(Date date, String contents) {
      this.date = date;
      this.contents = contents;
   }

   @Override
   public boolean contains(String... textElements) {
      for (String text: textElements)
         if (contents.contains(text))
            return true;
      return false;
   }

   @Override
   public Date getDate() {
      return date;
   }
}
リスト2 Containsのテスト
import static org.junit.Assert.*;

import java.util.*;
import org.junit.*;

public class ContainsTest {
   private static final String CONTENTS = "these are the contents";
   private TextDocument document;

   @Before
   public void createDocument() {
      document = new TextDocument(new Date(), CONTENTS);
   }

   @Test
   public void failsWhenTextNotInContents() {
      Expression expression = new Contains(CONTENTS + "x");
      assertFalse(expression.evaluate(document));
   }

   @Test
   public void passesWhenTextInContents() {
      String text = "contents";
      assertTrue(CONTENTS.indexOf(text) != -1);

      Expression expression = new Contains(text);
      assertTrue(expression.evaluate(document));
   }
}

 Interpreterパターンを使用してインタープリタを作成するための基本的な方法は、必要な文法を一連のクラスへと変換することです。1個のクラスは文法の各規則を表し、そのクラスのフィールドは規則の変換先のシンボルを表します。例えば、今回のサブ文法には次のような規則があります。

And ::= Expression 'and' Expression

 つまり、今回のInterpreterパターンの実装には、2つのフィールドを持つAndという名前のクラスがあり、それぞれのフィールドにはExpressionオブジェクトが1つずつ格納されます(私はいつも、「and」などのテキストを表す独立したオブジェクトを作成する代わりに、それを今回のAndのような規則クラスのコードに直接組み込むようにしています)。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • japan.internet.com(ジャパンインターネットコム)

    japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.com や EarthWeb.c...

  • Jeff Langr(Jeff Langr)

    本格的なソフトウェアの開発に四半世紀以上携わってきたベテランのソフトウェア開発者。『Agile Java: Crafting Code With Test-Driven Development』(Prentice Hall、2005年)と、他の1冊の著書がある。『Clean Code』(Uncle...

バックナンバー

連載:デザインパターンの使い方

もっと読む

All contents copyright © 2005-2018 Shoeisha Co., Ltd. All rights reserved. ver.1.5