Interpreterデザインパターンは、非常にプログラミング言語よりのパターンだ。自分で、新しくて、それでいながら簡易なプログラミング言語をデザインするときに使う事になるだろう。それ以外の場合は、なかなかお目にかかれないパターンだ。
Cocoaにそのようなパターンを使っているクラスがあるのだろうか? 実は、ピッタリのものがある。それは、Core Dataで使われている、オブジェクトを抽出するための文法だ。
Cocoa Predicates
Core Dataは、MVCアーキテクチャでいうと、モデルをサポートするものとなる。モデルクラスの作成を強力にバックアプする。クラスのモデリングのための専用ツールを用意し、データの永続性をほぼ完全に実現している。
Core Dataは、その出自にEnterprise Objects Framework (EOF)の技術がある。EOFもCocoaと並んでNeXT社の遺産であり、これをデスクトップアプリケーション用にカスタマイズしたものがCore Dataとなる。EOFは、データベースに接続するための技術だ。したがって、Core Dataにもデータベースの影響が見え隠れする。
データベースにアクセスする場合、クエリーを使うのが一般的だ。データベースにあるオブジェクトの集合から望みのものを抽出するために、その条件をある文法に従って記述するのだ。通常のデータベース技術では、SQLが使われているだろう。
Core Dataは、その設計思想を読むと、データベース技術とは一線をひきたがっているように感じる。サーバクライアントモデルを前提とするデータベースの設計と、デスクトップアプリケーションの設計は相容れない、という考え方らしい。そのためか、Apple社はCore Dataのオブジェクトを抽出するために、SQLは使わず、新しい文法を定義してきた。これが、Cocoa Predicatesと呼ばれるものだ。この文法の定義は、「BNF Definition of Cocoa Predicates」で確認する事が出来る。
Cocoa Predicatesのためのクラス
このCore Dataのための新しい文法、Cocoa Predicatesだが、通常はテキストで記述する事になる。それに加えて、実は、この文法をサポートするためのクラス群が存在するのだ。つまり、文法の1つ1つに対応するクラスがある。これは正に、Interpreterパターンそのものであると言えるだろう。
そのクラスを紹介しよう。まず、NSPredicateクラス。そのサブクラスであるNSComparisonPredicateとNSCompoudPredicate。そして、NSExpressionだ。
これらが、文法の1つ1つと対応している。
たとえば、論理演算を表す文法を見てみよう。Cocoa Predicatesでは、AND、OR、NOTといった文法がサポートされている。
NSCompoundPredicate ::= NSPredicate "AND" NSPredicate
| NSPredicate "OR" NSPredicate
| "NOT" NSPredicate
この文法に対応するクラスが、NSCompoundPredicateクラスだ。このクラスでは、次のようなメソッドを提供している。
+ (NSPredicate*)andPredicateWithSubpredicates:(NSArray*)subpredicates;
+ (NSPredicate*)orPredicateWithSubpredicates:(NSArray*)subpredicates;
+ (NSPredicate*)notPredicateWithSubpredicate:(NSPredicate*)predicate;
上から順に、AND、OR、NOTに対応している。ANDとORは、2つのNSPredicateを含む配列を渡して作成する事になっている。正に、論理演算のためのクラスだ。
比較演算子もチェックしておこう。Cocoa Predicatesでは、次のような文法になっている。
operation ::= "=" | "!=" | "<" | ">" | "<=" | ">="
| BETWEEN
| aggregate_operations [ "[" string_options "]" ]
aggregate_operations ::= CONTAINS | IN | string_operations
string_operations ::= BEGINSWITH | ENDSWITH | LIKE | MATCHES
string_options ::= c | d | cd
これに対応するクラスが、NSComparisonPredicateだ。このクラスには、次のようなメソッドがある。
+ (NSPredicate*)predicateWithLeftExpression:(NSExpression*)lhs
rightExpression:(NSExpression*)rhs
modifier:(NSComparisonPredicateModifier)modifier
type:(NSPredicateOperatorType)type
options:(NSUInteger)options;
まず、比較演算の左側と右側に来るNSExpressionを指定する。次に、modifierを指定する。これは、文法で言うとaggregate_qualifierに対応するものだ。その次は、typeになる。これは比較演算のタイプを表し、operationとaggregate_operationsに対応している。
このような感じで、文法に対応するクラスが用意されている訳だ。これは正に、Interpreterパターンそのものであろう。
グラフィカルなルールエディタ
文法に対応するクラスを提供する目的は、アプリケーション中で動的に、その文法を使った文を書けるようにすることだ。ここでも、Core Dataは非常にCocoaらしいソリューションを提供している。すなわち、グラフィカルなルールエディタを提供しているのだ。
これについては、実際に見てもらった方が早いだろう。次のような、Cocoa Predicatesに対応したルールエディタが用意されている。
ANDやORといった演算子を、GUIを使って指定しながら、文を書く事が出来るのだ。文法をクラス化する、Interpreterパターンの最も有効な活用方法と言っていいだろう。