どうもはまじです.
 今回はデザインパターンのStrategyパターンについてご紹介したいと思います.

Strategyパターン

例えば,じゃんけんのプログラムを書きました.
このUserクラスは,ずっとグーを出し続ける戦略を採っています.

enum Hand {
    BLOCK,
    SCISSORS,
    PAPER;
}


class User {
    private String name;
    private int wons;


    public Hand getHand() {
        return Hand.BLOCK;
    }
}

このクラスのインスタンスだけでじゃんけん大会すると...結果は悲惨なことにw
なので,別の戦略を持ったユーザクラスを作りたい... と思ってはいけません!

※悪い例

class RandomHandUser extends User {
    private static Hand[] hands;
    static {
        hands = new Hand[]{ Hand.BLOCK, Hand.SCISSORS, Hand.PAPER };
    }
    @Override
    public Hand getHand() {
        return hands[(int)Math.random() * 3];
    }
}

さて,これで何が問題なのかJavaに詳しい人は一発でわかるでしょう.
そう,nameとwonsが名前解決できません
何故なら,Userクラスで定義された上記フィールドはそれぞれprivateなため,子クラスに継承されません.

ならばprotectedにすればいい?いえいえ,それは設計の過ちです.
protectedはabstractクラスなど,ほぼ継承されることがわかっているときに使えばよく,Userクラスのような通常のデータはprivateであるべきです.

ではどうすればいいのでしょうか.

答えは,Userクラスの中に戦略フィールドを用意することです

どういうことかというと,今まではUser#getHandの中で実装していましたが,これを別のクラスに委譲してやればいいのです.

まずは,「getHand()を呼べば,何かしらのHand型が返ってくるメソッドが必要」であると考えられます.
Userクラスでも同じメソッド名で呼び出しますが,そうではなく「じゃんけんの戦略に対してgetHandする」という考えを持ってみます.

そうすると,必然的に次のインターフェースが思い浮かぶことになります.

interface HandStrategy {
    public Hand getHand();
}

ではこの戦略を実装した,「グーしか出さない戦略クラス」を作りましょう.

class OnlyBlockHandStrategy implements HandStrategy {
    @Override
    public Hand getHand() {
        return Hand.BLOCK;
    }
}

という感じで,どんどん戦略クラスを作っていきます.
で,これらの戦略クラスをユーザが個別に持てるようにします.

class User {
    private String name;
    private int wons;
    private HandStrategy handStrategy;


    public Hand getHand() {
        return handStrategy.getHand();
    }
}

で,mainのコードはこうなりますね.

public static void main(String[] args) {
    User alice = new User();
    alice.setHandStrategy(new OnlyBlockHandStrategy());


    User bob = new User();
    bob.setHandStrategy(new OnlyScissorsHandStrategy());
    // …………
}

さて,ボブはアリスに全敗を喫し,高級寿司を奢らされる羽目になりました・・・.

という感じで,ひとつのクラスのとある区画(アルゴリズム)をごっそり入れ替えることができる,Strategyパターンについて紹介しました.

ちなみにこれ,こうすると見たことありませんか?

class User {
    @Autowired
    private HandStrategy handStrategy;
    // …………
}

そうですね,Spring Frameworkでも使用されているDependency Injectionですね.
どの戦略を入れるかはDIコンテナに依存し,中身をごっそり変えることができます.

もはや無意識のうちに使ってしまうぐらいの超頻出デザインパターンなので,ぜひ理解しましょうー