2014年3月19日水曜日

Specification Pattern を Java8のラムダで書いてみる

そろそろ Java SE 8 の GAリリースなので、ちょっと書いてみる。

お題は、DDD でよく使われる Specification Pattern にしてみよう。Wikipediaのこのエントリに、C#で書かれたコードが載ってるので、ざっと書き換えてみよう。
interface Specification<t> {
  boolean isSatisfiedBy(T t);

  default Specification<t> and(Specification<t> other) { 
    assert other != null;
    return t -> this.isSatisfiedBy(t) && other.isSatisfiedBy(t);
  } 
  default Specification<t> or(Specification<t> other) { 
    assert other != null;
    return t -> this.isSatisfiedBy(t) || other.isSatisfiedBy(t);
  } 
  default Specification<t> not() { 
    return t -> !isSatisfiedBy(t);
  } 
}
だいたいこんな感じになる。元のコードよりだいぶ簡単になった。

試しに動かしてみるコードが以下。
public class Test {
  public static void main(String[] args) {
    Specification<String> shortString = s -> s.length() < 3;
    Specification<String> startsWithA = s -> s.length() > 0 && s.charAt(0) == 'a';

    System.out.println(shortString.not().isSatisfiedBy("bcdefg"));// true
    System.out.println(shortString.and(startsWithA).isSatisfiedBy("bc"));// false
    System.out.println(shortString.or(startsWithA).isSatisfiedBy("bc"));// true
  }
}
実は、この Specificationと同じような Predicate というインターフェイスが、すでに java.util.function パッケージ配下にあったりする。

ただ、単なる predicate(述語) というよりもっと具体的に specification(仕様)という意味で使う文脈だと、やはり test() より isSpecifiedBy() の方が良いし(Evans と Fowler の元の記事でもそうなってる)、negate() より not() の方がいいように思う。

0 件のコメント:

コメントを投稿