ストラテジー・モードのメリットとデメリットの説明シーンの使用例とコード・プレゼンテーション
7712 ワード
一言で言えば
クラスの動作またはアルゴリズムは、実行時に変更できます.
補足:
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テスタのクラス
コード:
実行結果:
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}
クラスの動作またはアルゴリズムは、実行時に変更できます.
補足:
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}