yojikのlog

yojikのブログです

流れないインタフェース

最近(でもないんだけど)話題の流れるようなインタフェース
Smalltalkスタイルの流れるようなインタフェースって、確かに素敵っぽいけど、複雑な階層構造のオブジェクトを構築する際に辛いことが多い。(もちろんSmalltalkはカスケード式やブロックがあるから、もう少し状況が違うかもしれない)

object.with(a).with(b)

こんな風にobjectの属性や子供をどんどん追加するコードは簡単に書けるけど、ツリー構造を組み立てるコードは書きづらい。上記の例だとオブジェクトaに何か属性や子供を追加するのは困難。
内部に呼び出し階層のスタック?を用意して、jQueryのend()メソッドみたいなのを導入するしかない。

obj.child(a)   //ここでchildメソッドはオブジェクトaを返り値とする
     .with(aa) //ここではオブジェクトaのthisを返す
     .with(ab) //ここではオブジェクトaのthisを返す
   .end()      //ここで呼び出し階層の一個上(obj)を返却する
   .child(b)   //childにbを追加して、返り値はb

まぁこれでもいいんだけど、オブジェクト本来のロジックとは関係ないスタック用のデータ構造やメカニズムを持たせる必要があるのはめんどい。あと、自動インデントに弱いのもいまいち。

というわけで流れないインタフェース

現在のJavaで、ツリー構造の構築を上手く扱いたい場合は、static importと可変長引数を使った方が簡単でいいと思う。
具体的にはこんな感じ。
JSONのデータ構造を作る例

JSONObject obj = object(
  member("bookmark", 
         object(
           member("title", val("example")),
           member("url",   val("www.example.com"))
           )
         ),
  member("comments",
         array(
           object(
             member("name",val("yojik")),
             member("comment",  val("あとで読む"))
             ),
           object(
             member("name",val("aaa")),
             member("comment",  val("あとで読まない"))
             ),
           object(
             member("name",val("bbb")),
             member("comment",  val("これはひどい"))
             )					
           )
         ))				
        );

なんとなく眺めているだけで、データ構造が見えてくると思う。JSONの仕様っぽく作ってある。
で、これを実現するためのコードはめっちゃ簡単である。

package builders;
public class JSONBuilder {
    public static <T> JSONValue<T> val(T obj) {
        return new JSONValue<T>(obj);       
    }
    public static JSONMember member(String name, JSONElement value) {
        return new JSONMember(name, value);
    }
    public static JSONArray array(JSONElement... elms) {
        return new JSONArray(elms);
    }
    public static JSONObject object(JSONMember... members) {
        return new JSONObject(members);
    }
}

こんな感じのBuilderクラスを作成して、staticインポートするだけ。*1

import static builders.JSONBuilder.*;

オブジェクトの組み立て部分は簡易DSLのように見えてわかりやすい。多分Genericsを使えば、型の安全をもっと厳密に保障するようにコーディングすることも可能だと思う。Builderクラスのメソッドの設計をきちんとするだけで、それ以外の実装にほとんど気をつかわないで済むのもいい。同じものを「流れるようなインタフェース」で作るのは相当面倒だろう。
流れるようなインタフェースは副作用を上手く使って、ちょっとずつ構造を組み立て行くイメージだけど、こちらは、一気にバシッと組み立てる感じ。
もちろん欠点もある。構造の一部分を動的に組み立てるとかは圧倒的に弱そう。まぁ適材適所というものがあるのだろう。SQLの組み立てにどちらが向いているか?、混在させることは可能か?、分からないことが多い。まだまだ研究が必要かも。

*1:各クラスは省いているけど大体わかるよね