Project Euler Problem 10を例にトランザクションスクリプトとドメインモデル
トランザクションスクリプトとドメインモデルの理解のために。しつこいくらいが丁度いいw
アルゴリズムおよびコードの大部分はhttp://d.hatena.ne.jp/pgf2/20080527/1211868834より拝借しています。ありがとうございます!
コードと概略
- Transaction Scriptブロックでは、3つのprivate staticメソッドを組み合わせて使っています。
- primes()で素数の配列を取得し、sum()で配列の合計値を取得しています。
- Domain Modelブロックでは、内部クラスであるPrimesクラスを使っています。
- primesオブジェクトのsum()から、素数の合計値を取得しています。
- Problem 10では200万以下の素数の合計となってるけど、計算に時間がかかるので、試用向けに10万以下としています。
import java.util.*; /** * Project Euler Problem 10 */ public class Problem10 { public static void main(String[] args) { int max = 100000; { //Transaction Script long start = System.currentTimeMillis(); System.out.println(Problem10.sum(Problem10.primes(max))); long end = System.currentTimeMillis(); System.out.println("time:"+ (end - start)); } { //Domain Model long start = System.currentTimeMillis(); System.out.println(new Primes(max).sum()); long end = System.currentTimeMillis(); System.out.println("time:"+ (end - start)); } } private static Long[] primes(long maxval){ Deque<Long> primes = new ArrayDeque<Long>(); primes.add(2L); for (long val=3L; val<=maxval; val+=2) if (isPrime(val, primes)) primes.add(val); return primes.toArray(new Long[primes.size()]); } private static boolean isPrime(long val, Collection<Long> que) { boolean noPrime = false; for (long prime : que) { if (val / 2 < prime) { break ; } else if (val % prime == 0) { noPrime = true; break ; } } return !noPrime; } private static long sum(Long[] vals) { long sum = 0; for (Long val : vals) sum += val.longValue(); return sum; } public static class Primes { public final int maxValue; public final Collection<Long> primes; private ArrayDeque<Long> que = new ArrayDeque<Long>(); private Long sum; public Primes(int maxValue) { this.maxValue = maxValue; que.add(2L); for (long val = 3L; val <= maxValue; val+=2) if (isPrime(val)) que.add(val); this.primes = Collections.unmodifiableCollection(que); } public long sum() { if (sum != null) return sum; sum = 0l; for (Long val : primes) sum += val; return sum; } private boolean isPrime(long val) { for (long prime : que) { if (val / 2 < prime) return true; if (val % prime == 0) return false; } return true; } } }
考察
- 拝借した元コードではメソッドは非staticで定義されていましたが、クラスのインスタンスとは無関係のため、staticにしてみました。
- というか、なぜか微妙に早くなってます。Transaction Scriptが2800前後なのに対して、Domain Modelが2500前後。
- トランザクションスクリプトとドメインモデルでは、利用者の利用方法が違うのはわかる。
- 「Problem10.sum(Problem10.primes(max))」を「Problem10.sumOfPrimes(max)」としても同様。Problem10っていうサーバに規定されたサービスから結果のみを取り出す方式。
- Primes#sum()について。メソッドで取得するのではなく下記のようにして、「primes.sum」を参照してもらう方法でもアリだと思う。
//private long sum; public final long sum; //... private long sum() { //... }