1. 程式人生 > >23種設計模式----策略模式----行為型模式

23種設計模式----策略模式----行為型模式

策略模式

1.什麼是策略模式

首先,什麼策略:策略是與敵軍作戰的方法,慢慢擴充套件為做事情的方式;在程式設計中,可以理解為“演算法”。
那麼,在程式設計中,要實現同一個需求,有不同的演算法來實現,這些演算法有好有壞,而且不同的演算法有不同的特點。所以,如果程式根據需要,動態的切換演算法,實現功能就比較完善。
策略模式就是為了解決整體的替換演算法的這一問題。
策略模式的核心:
委託,模板方法。
使用模板方法達到不同的實現,使用委託達到不同的例項替換。

2.角色

抽象策略—Strategy
具體的策略—StrategyImpl
策略的使用—play

3.例子–骰子-大小–猜大小

說起骰子,最簡單的就是猜大小的遊戲。也是被認為最公平的遊戲(不是嗎,本例就來驗證)
說起玩骰子,幾乎每個人都玩過,也都會玩:

要玩骰子,需要一些條件:
骰子、莊家、玩家

3.1骰子–實體

import java.util.Random;

/**
 * 骰子實體
 * 作為骰子,一定是一局遊戲中使用同一副骰子
 * 所以,把骰子設計為單例模式
 */
public class Dice {

	//骰子個數
	private static Integer number;
	
	//使用類載入時建立例項,餓漢式。
	private static final Dice DICE = new Dice(); 

	public static Dice getInstance(){
		return DICE;
	}
	
	private Dice(){
	}
	
	public static Integer getDice(){
		if(number != null)
			return new Random().nextInt(number*6);
		else{
			System.out.println("please input the Dice number");
			return null;
		}
	}

	public static Integer getNumber() {
		return number;
	}

	public static void setNumber(Integer number) {
		Dice.number = number;
	}
	
}

3.2策略

想要贏是需要動腦子的

/**
 * 策略介面
 * 1.給出點數
 * 2.設定輸贏
 */
public interface Strategy {

	/**
	 * 玩的是壓大小的遊戲
	 * 所以0 == 小
	 *  1 == 大
	 */
	public Integer getCount();
	
	/**
	 * true表示贏
	 * false表示輸
	 */
	public void setWin(Integer integer);
	
}

3.3乘勝追擊–具體的策略

乘勝追擊–上一把骰子的結果是大,我就壓大,上一把骰子結果是小,我就壓小。

/**
 * 乘勝追擊
 * 策略:上一局的點數作為本次壓的點數
 * (與勝負無關)
 */
public class FollowWin implements Strategy{

	//上一局的點數
	private Integer lastNumber = 0;
	
	public Integer getLastWinNumber() {
		return lastNumber;
	}

	public void setLastWinNumber(Integer lastWinNumber) {
		this.lastNumber = lastWinNumber;
	}

	@Override
	public Integer getCount() {
		return lastNumber;
	}

	@Override
	public void setWin(Integer integer) {
		
	}

}

3.4 反其道而行

上一把骰子結果為大,這把我就壓小;上一把骰子結果為小,這把我就壓大。

/**
 * 反其道而行,上一局相反的點數作為本局壓的點數
 * (與勝負無關)
 */
public class OppositeWin implements Strategy{

	private Integer lastNumber = 0;
	
	private Integer num;
	
	public OppositeWin(Integer num){
		this.num = num;
	}
	
	public Integer getLastNumber() {
		return lastNumber;
	}

	public void setLastNumber(Integer lastNumber) {
		this.lastNumber = lastNumber;
	}

	@Override
	public Integer getCount() {
		return 6*num + 1 - lastNumber;
	}

	@Override
	public void setWin(Integer integer) {
		
	}

}

3.5統計規律

哪個點數出現的最多,我壓哪個點數(這個點數可能為大,也可能為小)

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 熱點數
 * 哪一個點數出現的次數最多,下一局使用哪個點數
 *
 */
public class HotWin implements Strategy{

	//需要初始化map
	private Map<Integer, Integer> map = new HashMap<Integer, Integer>();
	
	public HotWin(Integer num) {
		
		initMap(num);
	}

	private Integer getMax(){
		Integer maxKey = null;
		Integer maxValue = null;
		Iterator<Integer> iterator = map.keySet().iterator();
		while(iterator.hasNext()){
			Integer s = iterator.next();
			if(maxKey == null || maxValue == null){
				maxKey = s;
				maxValue = map.get(s);
			}else if(maxValue < map.get(s)){
				maxKey = s;
				maxValue = map.get(s);
			}
		}
		return maxKey;
	}
	
	private void initMap(Integer num){
		for(Integer i = 1;i <= num*6;i++){
			map.put(i, 0);
		}
	}
	
	@Override
	public Integer getCount() {
		return getMax();
	}

	@Override
	public void setWin(Integer integer) {
		Integer tmp = map.get(integer);
		map.remove(integer);
		map.put(integer, ++tmp);
	}

}

3.6玩家

/**
 * 遊戲者
 * 1.壓大小
 * 2.獲取點數,知曉輸贏
 * 3.知道現在是幾個骰子
 */
public class Player {

	private String name;
	
	private Strategy strategy;
	
	private Integer num;
	
	private Integer win = 0;
	
	private Integer lose = 0;
	
	public Player(Strategy strategy,Integer num,String name){
		this.strategy = strategy;
		this.num = num;
		this.name = name;
	}
	
	public String getStrategy(){
		return strategy.getClass().getName();
	}
	
	/**
	 * 返回true表示壓小
	 * false表示壓大
	 * @return
	 */
	public Boolean getBoolean(){
		return strategy.getCount() <= 3*num ;
	}
	
	public void setWin(Integer dice,Boolean bool){
		//bool表示遊戲結果(大還是小)
		if(bool == getBoolean()){
			strategy.setWin(dice);
			win++;
		}else{
			strategy.setWin(dice);
			lose++;
		}
	}

	public Integer getNum() {
		return num;
	}

	public Integer getWin() {
		return win;
	}

	public Integer getLose() {
		return lose;
	}

	public String getName() {
		return name;
	}

}

3.7莊家(mian類)

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		
		Scanner scanner = new Scanner(System.in);
		System.out.println("骰子個數");
		int diceCount = scanner.nextInt();
		System.out.println("遊戲局數");
		long gameCount = scanner.nextLong();
		//1.獲取骰子例項,1個骰子
		Dice.setNumber(diceCount);
		
		//2.初始化遊戲者
		Player xiaoming = new Player(new FollowWin(), diceCount,"小明");
		Player xiaohu = new Player(new OppositeWin(diceCount), diceCount, "小虎");
		Player redian = new Player(new HotWin(diceCount), diceCount, "熱點");
		
		//3.進行遊戲
		long nowCount = 1;
		while(nowCount <= gameCount){
			System.out.println("現在是第"+nowCount+"場遊戲");
			System.out.println(xiaoming.getName()+"\t壓\t"+(xiaoming.getBoolean()?"小":"大"));
			System.out.println(xiaohu.getName()+"\t壓\t"+(xiaohu.getBoolean()?"小":"大"));
			System.out.println(redian.getName()+"\t壓\t"+(redian.getBoolean()?"小":"大"));
			Integer number = Dice.getDice()+1;
			System.out.println("點數是"+number+"點");
			Boolean bool = number <= Dice.getNumber()*3;
			System.out.println("結果是\t" + (bool ? "小":"大"));
			
			//通知遊戲者本局的點數和結果
			xiaoming.setWin(number, bool);
			xiaohu.setWin(number, bool);
			redian.setWin(number, bool);
			nowCount++;
		}
		
		//4.輸出彙總
		System.out.println("總共"+gameCount+"局遊戲");
		System.out.println();
		collect(xiaoming);
		System.out.println();
		collect(xiaohu);
		System.out.println();
		collect(redian);
		
		
	}

	private static void collect(Player player){
		System.out.println("我是"+player.getName());
		System.out.println("我贏了"+player.getWin()+"局");
		System.out.println("我輸了"+player.getLose()+"局");
		System.out.println("我使用的是"+player.getStrategy()+"策略");
	}
}

3.8 1個骰子,100局,哪個策略勝率大

後面省略過程,只輸出結果(迴圈內的輸出註釋掉即可)
結尾傳送門

骰子個數
1
遊戲局數
100
現在是第1場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第2場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是2點
結果是	小
現在是第3場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是6點
結果是	大
現在是第4場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第5場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第6場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是4點
結果是	大
現在是第7場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是3點
結果是	小
現在是第8場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是6點
結果是	大
現在是第9場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是3點
結果是	小
現在是第10場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第11場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是5點
結果是	大
現在是第12場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是6點
結果是	大
現在是第13場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是1點
結果是	小
現在是第14場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是5點
結果是	大
現在是第15場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是6點
結果是	大
現在是第16場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是6點
結果是	大
現在是第17場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是1點
結果是	小
現在是第18場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是3點
結果是	小
現在是第19場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是3點
結果是	小
現在是第20場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是3點
結果是	小
現在是第21場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是1點
結果是	小
現在是第22場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是6點
結果是	大
現在是第23場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是4點
結果是	大
現在是第24場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是1點
結果是	小
現在是第25場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是5點
結果是	大
現在是第26場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是2點
結果是	小
現在是第27場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是3點
結果是	小
現在是第28場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是6點
結果是	大
現在是第29場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是4點
結果是	大
現在是第30場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是1點
結果是	小
現在是第31場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是2點
結果是	小
現在是第32場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是5點
結果是	大
現在是第33場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是4點
結果是	大
現在是第34場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是6點
結果是	大
現在是第35場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是1點
結果是	小
現在是第36場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是2點
結果是	小
現在是第37場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是1點
結果是	小
現在是第38場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是3點
結果是	小
現在是第39場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是2點
結果是	小
現在是第40場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	大
點數是1點
結果是	小
現在是第41場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第42場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是1點
結果是	小
現在是第43場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是1點
結果是	小
現在是第44場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第45場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第46場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是2點
結果是	小
現在是第47場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第48場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是6點
結果是	大
現在是第49場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第50場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第51場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第52場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是1點
結果是	小
現在是第53場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第54場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第55場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第56場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第57場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第58場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是2點
結果是	小
現在是第59場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是2點
結果是	小
現在是第60場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是2點
結果是	小
現在是第61場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是1點
結果是	小
現在是第62場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第63場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是1點
結果是	小
現在是第64場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第65場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是6點
結果是	大
現在是第66場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第67場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第68場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第69場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第70場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第71場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是1點
結果是	小
現在是第72場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是1點
結果是	小
現在是第73場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第74場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第75場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是1點
結果是	小
現在是第76場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第77場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第78場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第79場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是2點
結果是	小
現在是第80場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第81場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第82場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第83場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第84場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是2點
結果是	小
現在是第85場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第86場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是2點
結果是	小
現在是第87場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第88場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第89場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第90場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第91場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是6點
結果是	大
現在是第92場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是5點
結果是	大
現在是第93場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是3點
結果是	小
現在是第94場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是6點
結果是	大
現在是第95場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是1點
結果是	小
現在是第96場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
現在是第97場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是2點
結果是	小
現在是第98場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是1點
結果是	小
現在是第99場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是2點
結果是	小
現在是第100場遊戲
小明	壓	小
小虎	壓	大
熱點	壓	小
點數是4點
結果是	大
總共100局遊戲

我是小明
我贏了53局
我輸了47局
我使用的是cn.com.startimes.strategy.FollowWin策略

我是小虎
我贏了47局
我輸了53局
我使用的是cn.com.startimes.strategy.OppositeWin策略

我是熱點
我贏了47局
我輸了53局
我使用的是cn.com.startimes.strategy.HotWin策略

開頭傳送門

3.9 10個骰子,100000局

骰子個數
10
遊戲局數
100000
總共100000局遊戲

我是小明
我贏了50228局
我輸了49772局
我使用的是cn.com.startimes.strategy.FollowWin策略

我是小虎
我贏了49772局
我輸了50228局
我使用的是cn.com.startimes.strategy.OppositeWin策略

我是熱點
我贏了50197局
我輸了49803局
我使用的是cn.com.startimes.strategy.HotWin策略

3.10 1000個骰子,10 0000 局

總共100000局遊戲

我是小明
我贏了50248局
我輸了49752局
我使用的是cn.com.startimes.strategy.FollowWin策略

我是小虎
我贏了49752局
我輸了50248局
我使用的是cn.com.startimes.strategy.OppositeWin策略

我是熱點
我贏了50131局
我輸了49869局
我使用的是cn.com.startimes.strategy.HotWin策略

4.總結

可以看到我們對壓大小的策略使用了策略模式,但是現在實現的只有一個壓大小,因為是play這個類實現委託的,所以,能否對play類使用策略模式,完成不同的玩法,壓點數,奇偶等等。。。

另一個看到我們模擬這麼多次試驗,骰子出現大小的機率幾乎是相等的,所以說,壓大小几乎是最公平的遊戲。