ストラテジー・モードのメリットとデメリットの説明シーンの使用例とコード・プレゼンテーション


一言で言えば
クラスの動作またはアルゴリズムは、実行時に変更できます.
補足:
Strategy Patternでは、クラスの動作またはそのアルゴリズムを実行時に変更できます.このタイプの設計モードは動作モードに属します.
Strategyとは「策略」を意味し、敵軍と対峙する際に行軍して戦う方法を指す.
ポリシーモードでは、ポリシーを表す様々なオブジェクトと、ポリシーオブジェクトが変化するにつれて動作が変化するcontextオブジェクトを作成します.ポリシーオブジェクトはcontextオブジェクトの実行アルゴリズムを変更します.
一連のアルゴリズムを定義し、ポリシーオブジェクトを1つずつカプセル化し、互いに置き換えることができます.
主な解決は、複数のアルゴリズムが似ている場合にifを使用することです.elseがもたらす複雑さとメンテナンスが困難です.
参加ロール:
1)ポリシークラスの抽象ベースクラス(インタフェースであってもよい)が異なるポリシークラスを持つ共有メソッド
2)各種戦略実現クラス
3)Contextクラス(ポリシーベースクラスを持つオブジェクトは、ポリシーオブジェクトの変更に伴って動的に動作を変えることができる)
メリット:
1)アルゴリズムは自由に切り替えることができる.
2)多重条件判定は避ける.
3)拡張性が良好である.
欠点:
1)ポリシークラスが増えます.
2)すべての戦略類は外部に暴露する必要がある.
使用例またはシーン:
1)諸葛亮の錦嚢の妙策は、それぞれの錦嚢が一つの策略である.
2)旅行の遊び方は、自転車に乗るか、車に乗るかを選択し、それぞれの旅行方法が一つの戦略である.
3)JAVA AWTのLayoutManager.
サンプルプログラム
ソースが必要な方はgithubでダウンロードできます.
https://github.com/aharddreamer/chendong/tree/master/design-patterns/demo-code/design-patterns
プログラムの概要:
次のプログラムの機能はコンピューターにじゃんけんゲームをさせることです.私たちは2つのじゃんけん戦略を考えました.1つ目の戦略は「もしこの試合が勝ったら、次の試合も同じジェスチャーをします」(VinningStrategy)で、これは少し愚かな戦略です.もう1つの戦略は「前のセットのジェスチャーから確率的に次のセットのジェスチャーを算出する」(ProbStrategy).
サンプル・プログラム・クラス/インタフェースの一覧:
Handはじゃんけんゲームの「ジェスチャー」を表す類(ツール)
Strategyは、じゃんけんゲームにおけるストラテジーのクラス(ストラテジークラスのベースクラス)を表す
WinningStrategyは「このセットが勝てば、次のセットも同じジェスチャーをする」というポリシーのクラス(具体的なポリシーオブジェクト1)
ProbStrategyは「前局のジェスチャーから確率的に次局のジェスチャーを算出する」というポリシーのクラス(具体的なポリシーオブジェクト2)を表す.
Playerはじゃんけんゲームを行うクラス(Context環境クラス)を表す
StrategyPatternTestテスタのクラス
 
コード:
public class Hand {
    public static final int SHI_TOU = 0; //      
    public static final int JIAN_DAO = 1; //      
    public static final int BU = 2; //      
    public static final Hand[] hand = {
            new Hand(SHI_TOU), new Hand(JIAN_DAO), new Hand(BU)
    };
    public static final String[] name = {
            "  ", "  ", " "
    };
    private int handValue;
    private Hand (int handValue) {
        this.handValue = handValue;
    }
    public boolean isStrongerThan(Hand hand) {
        return fight(hand) == -1;
    }
    public int fight(Hand hand) {
        if (this == hand) {
            return 0;
        }else if ((this.handValue + 1) % 3 == hand.handValue) {
            return 1;
        }else {
            return -1;
        }
    }
    public String toString() {
        return name[this.handValue];
    }
    public static Hand getHand(int handValue) {
        return hand[handValue];
    }
    public boolean isWeakerThan(Hand hand) {
        return fight(hand) == -1;
    }
}



public interface Strategy {
    Hand nextHand();
    void study(boolean vin);
}


public class WinningStrategy implements Strategy {
    private Random random;
    private boolean won = false;
    private Hand preHand;
    public WinningStrategy(int seed) {
        random = new Random(seed);
    }
    public Hand nextHand() {
        if (!won) {
            preHand = Hand.getHand(random.nextInt(3));
        }
        return preHand;
    }
    public void study(boolean win) {
        won = win;
    }
}

public class Player {
    private String name;
    private Strategy strategy;
    private int wincount;
    private int losecount;
    private int gamecount;
    //       
    public Player(String name, Strategy strategy) {
        this.name = name;
        this.strategy = strategy;
    }

    //            
    public Hand nextHand() {
        return strategy.nextHand();
    }
    public void win() {
        strategy.study(true);
        wincount++;
        gamecount++;
    }
    public void lose() {
        strategy.study(false);
        losecount++;
        gamecount++;
    }
    public void even() {
        gamecount++;
    }

    @Override
    public String toString() {
        return "Player{" +
                "name='" + name + '\'' +
                ", strategy=" + strategy +
                ", wincount=" + wincount +
                ", losecount=" + losecount +
                ", gamecount=" + gamecount +
                '}';
    }
}


public class ProbStrategy implements Strategy {
    private Random random;
    private int preHandValue = 0;
    private int currentHandValue = 0;
    private int[][] history = {
            {1, 1, 1, },
            {1, 1, 1, },
            {1, 1, 1, },
    };
    public ProbStrategy(int seed) {
        random = new Random(seed);
    }
    public Hand nextHand() {
        int bet = random.nextInt(getSum(currentHandValue));
        int handValue = 0;
        if (bet < history[currentHandValue][0]) {
            handValue = 0;
        }else if (bet < history[currentHandValue][0] + history[currentHandValue][1]) {
            handValue = 1;
        }else {
            handValue = 2;
        }
        preHandValue = currentHandValue;
        currentHandValue = handValue;
        return Hand.getHand(handValue);
    }
    private int getSum(int hv) {
        int sum = 0;
        for (int i = 0; i < 3 ; i++) {
            sum += history[hv][i];
        }
        return sum;
    }
    public void  study(boolean win) {
        if (win) {
            history[preHandValue][currentHandValue] ++;
        }else {
            history[preHandValue][(currentHandValue + 1) % 3] ++;
            history[preHandValue][(currentHandValue + 2) % 3] ++;
        }
    }
}

public class StrategyPatternTest {
    public static void main(String[] args) {
        //        seed
        /*if (args.length != 2) {
            System.out.println("Usage: java Main randomseed1 randomseed2");
            System.out.println("Example: java Main 314 15");
            System.exit(0);
        }
        int seed1 = Integer.parseInt(args[0]);
        int seed2 = Integer.parseInt(args[1]);*/
        int seed1 = 314;
        int seed2 = 15;
        Player player1 = new Player("WinningStrategyPlayer", new WinningStrategy(seed1));
        Player player2 = new Player("ProbStrategyPlayer", new ProbStrategy(seed2));
        for (int i = 0; i < 1000 ; i++) {
            Hand nextHand1 = player1.nextHand();
            Hand nextHand2 = player2.nextHand();
            if (nextHand1.isStrongerThan(nextHand2)) {
                System.out.println("Winner: " + player1);
                player1.win();
                player2.lose();
            }else if (nextHand2.isStrongerThan(nextHand1)) {
                System.out.println("Winner: " + nextHand2);
                player1.lose();
                player2.win();
            }else {
                System.out.println("Even...");
                player1.even();
                player2.even();
            }
        }
        System.out.println("Total Result: ");
        System.out.println(player1.toString());
        System.out.println(player2.toString());
    }
}


実行結果:
Winner: Player{name='WinningStrategyPlayer', strategy=org.cd.designpatterns.strategy.WinningStrategy@2ff4acd0, wincount=310, losecount=330, gamecount=993}
Winner:石
Winner: Player{name='WinningStrategyPlayer', strategy=org.cd.designpatterns.strategy.WinningStrategy@2ff4acd0, wincount=311, losecount=331, gamecount=995}
Even...
Winner:石
Even...
Even...
------(数行省略)------
Total Result:
Player{name='WinningStrategyPlayer', strategy=org.cd.designpatterns.strategy.WinningStrategy@2ff4acd0, wincount=312, losecount=332, gamecount=1000}
Player{name='ProbStrategyPlayer', strategy=org.cd.designpatterns.strategy.ProbStrategy@54bedef2, wincount=332, losecount=312, gamecount=1000}