天天看點

設計模式 - Strategy - 政策模式

Strategy模式:

  • 政策模式,我們可以把政策了解為算法,而政策模式就是我們将一個政策的實作委托給一個接口的實作類去實作,當我們隻要更換實作類就實作了政策的更換的目的,比如遊戲中的難度切換,也可以說是把AI接口的實作類切換了。

執行個體:

  • 模拟兩個選手猜拳,為了勝利,兩個選手選擇不同的政策,這裡兩個政策,一個是這次赢了,下次還做出同樣的選擇,如果輸了就随機出拳,而另一個則是,記錄下自己兩次出拳的勝利記錄,通過目前出拳,根據記錄來做出下次出拳赢面最大的選擇,這裡采用的是吧下次三種拳加起來,生成随機數,看它落在那個區域,赢面大的區域大,被選中的機率也就大。

Hand 類:

package com.zyy.pattern.beans;


public class Hand {
	private int handValue;
	public Hand(int handValue) {
		this.handValue = handValue;
	}
	
	
	
	public int getHandValue() {
		return handValue;
	}



	public static final Hand[] HANDS = new Hand[]{
			new Hand(0),
			new Hand(1),
			new Hand(2)
	};
	
	public static final String[] STRINGS = new String[] {
			"石頭",
			"剪刀",
			"布"
	};
	
	public static Hand getHand(int handValue) {
		return HANDS[handValue];
	}
	
	public boolean isStrongerThan(Hand h) {
		return  fight(h) == 1;
	}
	
	public boolean isEqual(Hand h) {
		return fight(h) == 0;
	}
	
	public boolean isWeakerThan(Hand h) {
		return fight(h) == -1;
	}
	public int fight(Hand h) {
		if(this.getHandValue() == h.getHandValue()) {
			return 0;
		} else if((this.getHandValue() + 1) % 3 == h.getHandValue()) {
			return 1;
		}else {
			return -1;
		}
	}
}

           

Strategy 接口:

package com.zyy.pattern.service;

import com.zyy.pattern.beans.Hand;

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

           

WinningStrategy 類:

package com.zyy.pattern.beans;

import java.util.Random;

import com.zyy.pattern.service.Strategy;

public class WinningStrategy implements Strategy{
	private Random random;
	private boolean won = false;
	private Hand prevHand;
	public WinningStrategy(long seed) {
		random = new Random(seed);
	}

	@Override
	public Hand nextHand() {
		if(!won) {
			prevHand =  Hand.getHand(random.nextInt(3));
		}
		return prevHand;
	}

	@Override
	public void study(boolean win) {
		won = win;
		
	}

}

           

ProbStrategy 類:

package com.zyy.pattern.beans;


import java.util.Random;

import com.zyy.pattern.service.Strategy;

public class ProbStrategy implements Strategy {

	private Random random;
	private int prevHandValue = 0;
	private int currentHandValue = 0;
	private int [][] history= {
			{1,1,1},
			{1,1,1},
			{1,1,1}
	};
	
	public ProbStrategy(long seed) {
		random = new Random(seed);
	}
	@Override
	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;
		}
		return Hand.getHand(handValue);
	}
	
	private int getSum(int currentHandValue) {
		int sum = 0;
		for(int i = 0;i < 3;i++) {
			sum += history[currentHandValue][i];
		}
		return sum;
	}

	@Override
	public void study(boolean win) {
		if(win) {
			history[prevHandValue][currentHandValue]++;
		}else {
			history[prevHandValue][(currentHandValue + 1) % 3]++;
			history[prevHandValue][(currentHandValue + 2) % 3]++;
		}

	}

}

           

Player 類:

package com.zyy.pattern.beans;

import com.zyy.pattern.service.Strategy;

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 + ", winCount=" + winCount + ", loseCount=" + loseCount + ", gameCount=" + gameCount
			+ "]";
}
 
 
}

           

測試執行個體以及測試結果:

public void StrategyPatternTest() {
		long seedFirst = 1;
		long seedSecond = 2;
		Player playerFirst = new Player("ke", new WinningStrategy(1));
		Player playerSecond = new Player("liang", new ProbStrategy(2));
		for(int i =0 ; i < 1000;i++) {
			Hand nextHandFirst = playerFirst.nextHand();
			Hand nextHandSecond = playerSecond.nextHand();
			logger.info("firstIsNull : {}",nextHandFirst == null);
			logger.info("secondIsNull : {}",nextHandSecond == null);
			if(nextHandFirst.isStrongerThan(nextHandSecond)) {
				logger.info("winner : {}",playerFirst);
				playerFirst.win();
				playerSecond.lose();
			}else if(nextHandFirst.isWeakerThan(nextHandSecond)) {
				logger.info("winner : {}",playerSecond);
				playerFirst.lose();
				playerSecond.win();
			}else {
				playerFirst.even();
				playerSecond.even();
			}
		}
		logger.info("playerFirst : {}",playerFirst);
		logger.info("playerSecond : {}",playerSecond);
	}
	
	
	21:53:59.739 [main] INFO testSpringFirst.DesignPatternTest - playerFirst : Player [name=ke, winCount=327, loseCount=336, gameCount=1000]
21:53:59.739 [main] INFO testSpringFirst.DesignPatternTest - playerSecond : Player [name=liang, winCount=336, loseCount=327, gameCount=1000]