ひがやすを技術ブログ

電通国際情報サービスのプログラマ

流れるようなインターフェースとメソッドチェーンは違うもの

っていうか、Hibernateにも昔からcriteriaあるよね?
http://www.hibernate.org/hib_docs/v3/reference/en/html_single/#querycriteria
List cats = sess.createCriteria(Cat.class)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list();

流れるようなインターフェースとメソッドチェーンは違うものだよヨシオリ。ぱっとみは似ているかもしれないけど。
流れるようなインターフェースでは、ソースコードを書いている人が、中断することなく流れるようにコーディングできなければいけない。
HibernateのCriteriaの例だとadd()で間違いなく手が止まる。きっとこう思うはずだ。add()の後に書くのは、Restrict...だったよなぁ。
もし、流れるようなインターフェースを意識しているならこうなるはず。


List cats = sess.createCriteria(Cat.class)
.like("name", "Fritz%")
.between("weight", minWeight, maxWeight)
.list();
流れるようなインターフェースは、うまく実装できれば、Javaのような静的言語と相性が良い。コード補完によって、流れがさらに滑らかになるから。
流れていないメソッドチェーンは、単にショートカットになんだと思う。
Hibernateの例で言えば、add()で追加している時点で、ショートカットの位置づけだと思う。
ファウラーたんの例を見て欲しい。
http://capsctrl.que.jp/kdmsnr/wiki/bliki/?FluentInterface

private void makeNormal(Customer customer) {
Order o1 = new Order();
customer.addOrder(o1);
OrderLine line1 = new OrderLine(6, Product.find("TAL"));
o1.addLine(line1);
OrderLine line2 = new OrderLine(5, Product.find("HPK"));
o1.addLine(line2);
OrderLine line3 = new OrderLine(3, Product.find("LGV"));
o1.addLine(line3);
line2.setSkippable(true);
o1.setRush(true);
}
これは、一般的な例だ。流れていないメソッドチェーンにすると次のようになる。

private void makeNormal(Customer customer) {
Order o1 = new Order()
.addLine(new OrderLine(6, Product.find("TAL")))
.addLine(new OrderLine(5, Product.find("HPK")).setSkippable(true))
.addLine(new OrderLine(3, Product.find("LGV")))
.setRush(true);
customer.addOrder(o1);
}
これを流れるようなインターフェースにするとこうなる。

private void makeFluent(Customer customer) {
customer.newOrder()
.with(6, "TAL")
.with(5, "HPK").skippable()
.with(3, "LGV")
.priorityRush();
}
単に書く文字が減ったとかそんな話ではない。思考を中断せずに流れるようにコーディングができるかどうかが重要なんだ。そして、よくできた流れるようなインターフェースは、可読性が高い。
「単なるメソッドチェーンとは違うのだよ!メソッドチェーンとは!」