くちたと計算記

プログラミングのことを書きます

テンプレートメソッドパターンの別解を考えたがクラスから知識が漏れ出しただけだった

テンプレートメソッドパターンとは振る舞いに関するデザインパターンの一つ。

ja.wikipedia.org

公開する振る舞いのうち一部をサブクラスでのみアクセス可能な抽象メソッドとして抽出している。 この方法を用いることで、公開する振る舞いの仕様を守りながら一部の処理をサブクラスで差し替えることができるようになっている。

別の実現方法として、抽象化している部分を別の抽象に委譲して、元の抽象クラスを具象クラスにすることもできるのではと思った。 関数型プログラミングでは抽象化した処理を関数の引数として扱うという話を聞いたので、クラス指向でもコンストラクタの引数を抽象化する解決策が有り得ると試してみた。 Wikipediaに載っている例を拝借すると、以下のようなコードになると思う。

class StringLister {
  private final StringListFormatter formatter;

  StringLister (StringListFormatter formatter) {
    this.formatter = formatter;
  }
  public String display(String[] items) {
      StringBuilder result = new StringBuilder(this.formatter.header());
      for (String item : items) {
          result.append(this.formatter.decorateItem(item));
      }
      result.append(this.formatter.footer());
      return result.toString();
  }
}

interface StringListFormatter {
  String header();
  String decorateItem(String item);
  String footer();
}

class PlainTextStringFormatter extends StringListFormatter {
  public String header() {
      return "";
  }
  public String decorateItem(String item) {
      return " - " + item + "\r\n";
  }
  public String footer() {
      return "";
  }
}

書いてみて思ったが、わたしが書いたコードは分かりづらい。 テンプレートメソッドパターンの方が以下の点で優れていると感じた。

  • 拡張方法が分かり易い。
  • リストの整形という知識を一つの型(StringLister)に閉じ込められている。

他のクラスに処理を委譲すると、何の知識も持たない抜け殻のようなクラスが生まれることがあることに気づけて良かったと思う。 クラスの持つ知識や責務の観点から気付きを得たが、高階関数を使った解法でも同じようなことは気になるものだろうか。 その細かい感覚を捉えられるほど、私はまだ関数型プログラミングをよく知らない。