関数の数珠つなぎ もしくは インタフェースの数珠つなぎ

JavaScriptで書いた関数の数珠つなぎ(http://d.hatena.ne.jp/taedium/20120310/p2)ですが、Javaでもやってみました。


JavaScript版とまったく同じ処理ではないですが、ある関数の実行結果を次の関数の引数としています。当然、型の制約を受けたりクロージャが使えなかったりするのでJavaScriptほど柔軟にはいかないですが、同じようなことができますね。

もうすこし汎用的にしようとすると、Func1, Func2みたいにジェネリクスつかったり別の型をつくったりしたくなります(.NETみたいに)けど、ここではシンプルにStringを受けてStringを返す関数をインタフェースであらわします。

package example;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Main {

  public static void main(String[] args) {
    Func func = chain(Arrays.asList(new A(), new B(), new C()));
    func.invoke("hoge");
  }

  private static Func chain(List<Func> functions) {
    Collections.reverse(functions);
    Func next = new NullFunc();
    for (final Func func : functions) {
      next = new AbstractFunc(next) {
        @Override
        public String invoke(String arg) {
          String result = func.invoke(arg);
          return this.next.invoke(result);
        }
      };
    }
    return next;
  }

  public interface Func {
    String invoke(String arg);
  }

  public static class NullFunc implements Func {

    @Override
    public String invoke(String arg) {
      return null;
    }

  }

  public static abstract class AbstractFunc implements Func {

    protected Func next;

    public AbstractFunc(Func next) {
      this.next = next;
    }
  }

  public static class A implements Func {
    @Override
    public String invoke(String arg) {
      System.out.println("A is called. arg: " + arg);
      return "aaa";
    }
  }

  public static class B implements Func {
    @Override
    public String invoke(String arg) {
      System.out.println("B is called. arg: " + arg);
      return "bbb";
    }
  }

  public static class C implements Func {
    @Override
    public String invoke(String arg) {
      System.out.println("C is called. arg: " + arg);
      return "ccc";
    }
  }

}


実行結果はこうなります。

A is called. arg: hoge
B is called. arg: aaa
C is called. arg: bbb