ジェネリクスとか、enumとか
特に意味は無いけど、ジェネリクスとかenumを使ってみよう。
// 関数のインターフェイス
public interface Function{
Y apply(X x);
}
まぁ、これはどこにでもあるようなインターフェイス。これを使って、ループを抽象化*1してみる。
何をやるかというと、ループの最初と最後の処理は普通の処理とは違う処理を施したいことが多い*2ので、それを支援できるようにしている。
public class Loop{ private Function
normalProc; // 通常の処理
private FunctionfirstProc; // 最初の処理
private FunctionlastProc; // 最後の処理
// 一個しか要素が無い場合の動作(デフォルトではlastProcを実行)
private ActionType actType = ActionType.LAST;
public static enum ActionType {
FIRST {
Y apply(Loop loop, X x) {
return loop.firstProc.apply(x);
}
}, NORMAL {
Y apply(Loop loop, X x) {
return loop.normalProc.apply(x);
}
}, LAST {
Y apply(Loop loop, X x) {
return loop.lastProc.apply(x);
}
};
// 関数を適用する(ジェネリックメソッド)
abstractY apply(Loop loop, X x);
}
public Loop(FunctionnormalProc) {
this.normalProc = normalProc;
this.firstProc = normalProc; // firstProcにも
this.lastProc = normalProc; // lastProcにもnormalProcを設定
}
// firstProcを設定しなおす
public void setFirstProc(FunctionfirstProc) {
this.firstProc = firstProc;
}
// lastProcを設定しなおす
public void setLastProc(FunctionlastProc) {
this.lastProc = lastProc;
}
// ループが一回しか回らない場合の動作を設定する
public void setActionType(ActionType actionType) {
this.actType = actionType;
}
// argsに対して何か処理を施し、結果を返す
public Listloop(List args) {
if (args == null || args.size() == 0)
return new ArrayList(0);
// 結果のリスト
Listresults = new ArrayList (args.size());
// 要素が一個だった場合、actTypeによって処理を振り分ける
if (args.size() == 1) {
results.add(actType.apply(this, args.get(0)));
return results;
}
// 2個以上ならイテレータを使用
Iteratoritr = args.iterator();
// このチェックは冗長すぎるかも・・・
if (itr.hasNext())
results.add(firstProc.apply(itr.next()));
while (itr.hasNext()) {
// とりあえず格納しておく
X x = itr.next();
// 次があるならまだ最後の要素じゃない
if (itr.hasNext())
results.add(normalProc.apply(x));
// 無いなら最後の要素ということ
else
results.add(lastProc.apply(x));
}
return results;
}
// 配列版
public Listloop(X args) {
return loop(Arrays.asList(args));
}
// テスト用メインメソッド
public static void main(String args) {
// 普通の処理では、引数の後ろに”, ”を追加する
Looplooper =
new Loop(new Function () {
public String apply(String str) {
return str.concat(", ");
}
});
// 最後の処理では、引数をそのまま返す
looper.setLastProc(new Function() {
public String apply(String str) {
return str;
}
});
// String配列に対してループを実行
Listresults = looper.loop(new String {
"hoge", "piyo", "foo", "bar"
});
// hoge, piyo, foo, barと出力される
for (String result : results)
System.out.print(result);
}
}
こんな感じで、結果の出力のループはごく単純なものになる。
まぁ、この程度だったらループ内にロジックを書いても問題ないけどね。
String strs = {"hoge", "piyo", "foo", "bar"};
for (int i = 0; i < strs.length; i++) {
if (i == strs.length - 1)
System.out.println(strs[i]);
else
System.out.print(strs[i].concat(", "));
}
・・・わかりにくいね*3。ただ、Loopクラス*4にはチェックされる例外を外に出せないという欠点がある*5。
それにしても、内部クラスに限ってはprivate abstractを許して欲しいような。