12/16/2010

[読書]ケント・ベック 実装パターン 

Kent Beck の実装パターンを読んだ。
日常的にコードを書く人ではない、趣味の園芸な自分が読んでも楽しめる。

一通り読んだものの咀嚼出来ていないところがあるので、時間を見つけて査読したいな。

ちょっと前に、Junitのソースコードを眺めていたんだけど、この本読んでる最中に、
「ああ、ここの記述はあそこのソースでもやってたなぁ」と思いだした。
もう一度、Junitちゃんと読んでみようかなぁ。

コレクションAPIのパフォーマンス比較をするために、測定用フレームワークを作っていて付録Aで
そのコードを公開している、コード自体はとても小さいシンプルなものだけど、本書の中のパターン
が使われている。

後でWebで見たかったので写経してみた。
コメントいれてる。変なところがあったら御免なさい。

このListSerchクラスのserchメソッドの実行時間を計測すると
search 25.30 77.81 551.10 と結果出力される。
要素数が増加すると実行時間が増えている。



import java.util.ArrayList;
import java.util.List;

public class ListSerch {
private List<Integer> numbers;
private int probe;

public ListSerch(int size){
numbers = new ArrayList<Integer>();
for (int i = 0; i < size; i++) {
numbers.add(i);
probe = size / 2;
}
}
//ArrayListの真ん中を取得させる。
public void search(){
numbers.contains(probe);
}
}

ドライバークラスは以下。
テストしたいクラスに含まれるメソッドの配列を引数にしてMethodsTimerインスタンス化。
report()メソッドを実行する。
結果はコンソールに
メソッド名 1回実行での時間 10回実行での合計時間 100回実行での合計時間 ・・・合計が1秒こえるまでやる。

public class TestDriver {

public static void main(String[] args) throws Exception{
MethodsTimer tester = new MethodsTimer(ListSerch.class.getDeclaredMethods());
tester.report();
}
}



import java.lang.reflect.Method;

public class MethodsTimer {
public final Method[] methods;
private static final int MAXIMUM_SIZE = 100;
public static final int ONE_SECOND = 1000000000;

public MethodsTimer(Method[] methods){
this.methods = methods;
}

public void report() throws Exception{
for(Method each : methods){
System.out.print(String.format("%.2f\t", r.getMethodTime()));
for (int size = 1; size <= MAXIMUM_SIZE; size *=10)
{
MethodTimer r = new MethodTimer(size, each);
r.run();
System.out.print(r.getMethodTime() + "\t");
}
System.out.println();
}
}
}



import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class MethodTimer {
private final int size;
private final Method method;
private Object instance;
private long totalTime;
private int iterations;
private long overhead;

public MethodTimer(int size, Method method) throws Exception{
this.size=size;
this.method=method;
instance = createInstance();
}

public MethodTimer(int iterations) throws Exception{
this(0,MethodTimer.Overhead.class.getMethod("nothing", new Class[0]));
this.iterations = iterations;
}

private static MethodTimer overheadTimer(int iterations) throws Exception{
return new MethodTimer(iterations);
}

private Object createInstance() throws Exception {
Constructor<?> constructor = method.getDeclaringClass().getConstructor(
new Class[] { int.class });
return constructor.newInstance(new Object[] { size });
}

double getMethodTime(){
return (double)(totalTime - overhead) / (double)iterations;
}


void run() throws Exception {
iterations = 1;
while (true) {
totalTime = computeTotalTime();
if (totalTime > MethodsTimer.ONE_SECOND)
break;
iterations *= 2;
}
overhead = overheadTimer(iterations).computeTotalTime();
}



private long computeTotalTime() throws Exception {
long start = System.nanoTime();
for (int i = 0; i < iterations; i++) {
method.invoke(instance, new Object[0]);
}
return System.nanoTime() - start;
}

public static class Overhead {
public Overhead(int size) { }
public void nothing() { }
}

}

0 件のコメント: