共通処理とラムダ式

近況

4月から某SI系企業に就職。 3ヶ月間の研修が終わり、7月から配属。

で、OJT…なんだけど次のプロジェクトが始まらないので、 前のプロジェクトのソース読んだり雑用したりしてる。

闇のソースリーディング

で、サーバサイドWebアプリのソースを勉強するという名目で JavaとかJavaScriptとかテキトーに読む日が続いてるんだけど、 まあ重複コードの多いこと。

例えばコントローラの各アクションで共通する処理 (認証情報の確認、チェックボックスの値のセット、等々)が ぜんぶベタ書きされてる。

流石にウンザリしたので、プロジェクトをコピーしてローカルで実行環境作って ソースをいじり回すことにした。

共通処理の抜き出し

匿名クラス

個別処理が関数として渡せるとすれば、 共通処理を行うメソッドはこんな感じに書きたい。

プロジェクトではPlay Framework使ってるのでそれっぽく。

private Result commonAction(/* 個別処理の関数 */func) {
  commonAction1();
  func();
  commonAction2();
  
  return ok();
}

ただJavaは関数が第一級オブジェクトじゃないので、 やるならクラス作って渡す必要がある。 匿名クラス使って個別処理も書くとこんな感じ。

private interface Func {
  void func(Object someArg);
}

private Result commonAction(Func func) {
  commonAction1();
  func.func(someArg);
  commonAction2();

  return ok();
}

public Result individualAction() {
  Func func = new Func() {
    public void func(Object someArg) {
      someOperation(someArg);
    };
  };

  return this.commonAction(func);
}

ラムダ式

で、ここまで書いて思い当たる。 何かこのインターフェース見たことあるなと。

あ、これConsumerじゃん。 関数型インターフェースじゃん。

じゃあラムダ式使って書き直しましょ。

private Result commonAction(Consumer<Object> consumer) {
  commonAction1();
  consumer.accept(someArg);
  commonAction2();

  return ok();
}

public Result individualAction() {
  return this.commonAction(someArg -> someOperation(someArg));
}