流れないインタフェース
最近(でもないんだけど)話題の流れるようなインタフェース。
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:各クラスは省いているけど大体わかるよね