突っ走り書き

見せるほどのものでは..

つまるところ,デザインパターンは

デザインパターンは,変化に強いコードを書くための戦略を集めたカタログです.
カタログであるが故に,自分の欲しいものが必ずしも見つかるとは限りません.
よって,「どのデザインパターンを使おうかなぁ」から始まるコーディングは不適切なやり方と言えます.
ボブおじさんも,次のように言っています.

デザインパターンを初めから意図的に取り込むといったやり方を私は勧めない.私が好む方法は,必要に応じてコードを進化させるやり方だ.(中略)改善する過程で,そのコードがある特定のデザインパターンに近づいていることに気がつくことがある.(中略)こうして,コードがデザインパターンに回帰していくのだ.

ーロバート・C・マーチン,アジャイルソフトウェア開発の奥義,24章冒頭ー

では,ボブおじさんの言う『改善』はどのように始まるのでしょうか?
このエントリでは,『改善』への出発点を,

  • 共通部分と特異部分を分ける作業

として,コードを進化させる過程を見ていきたいと思います.

勢いで書き下ろしたコード

整数のリストを引数とし,その中の偶数,または奇数の要素のみを取り出すメソッドを書きました.

public List<Integer> extractEven(List<Integer> src) {
    List<Integer> evens = new LinkedList<>();

    for (final int e : src) {
        if (e % 2 == 0) {
            evens.add(e);
        }
    }

    return evens;
}

public List<Integer> extractOdd(List<Integer> src) {
    List<Integer> odds = new LinkedList<>();

    for (final int e : src) {
        if (e % 2 == 0) {
            odds.add(e);
        }
    }

    return odds;
}

特異部分を取り出す

extraceEven と extractOdd は,ほとんどのコードが共通しています.
コードの特異部分は,for分の内側にあるif分の『条件』だけです.
特異な部分を,切り分けて,関数の外に追い出すのがオブジェクト指向です.
そこで,『条件』自体をオブジェクトにして関数の引数で渡すという改善をします.

public interface Condition<T> {

    boolean satisfies(T e);

}
public class IsEven implements Condition<Integer> {

    @Override
    public boolean satisfies(Integer e) {
        return e % 2 == 0;
    }

}
public class IsOdd implements Condition<Integer> {

    @Override
    public boolean satisfies(Integer e) {
        return e % 2 != 0;
    }

}

public <T> List<T> extract(List<T> src, Condition<T> condition) {
    List<T> extracted = new LinkedList<();

    for (final T e : src) {
        if (condition.satisfies(e)) {
            extracted.add(e);
        }
    }

    return extracted;
}

抽出条件を引数に渡して,extract 関数の動作を変えることができます.

public <Integer> extractEven(List<Integer> src) {
    return extract(src, IsEven);
}

public <Integer> extarctOdd(List<Integer> src) {
    return extract(src, IsOdd);
}

特異部分の『くくり出し』で変更に強くなる

今回は,if文の条件を特異部分として捉えるという極端な例を示しました.
ただ,このエントリで行ったことと,デザインパターンがやろうとしていることは本質的に同じです.
つまるところ,デザインパターン

  • 特異部分を取り出し方
  • 外部からの与え方

のカタログだからです.
カタログに無いような取り出し方であっても,それが必要ならばどんどん外部から与えるべきです.
変化に強いシステムを作りには,変化を外に追い出すほかに方法はありません.