博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一天一个设计模式——Strategy策略模式
阅读量:5243 次
发布时间:2019-06-14

本文共 6095 字,大约阅读时间需要 20 分钟。

一、模式说明

  策略模式比较好理解,就是将程序中用到的算法整体的拿出来,并有多个不同版本的算法实现,在程序运行阶段,动态的决定使用哪个算法来解决问题。

  举个实际的例子:排序算法的问题,假如我们的程序中需要对数据进行排序,我们知道,不同的算法具有不同的时间复杂度和空间复杂度,因此需要在程序运行时,根据可用内存和数据特征,选用不同的算法(排序策略),这就是策略模式的使用场景之一。再举个例子,负载均衡算法:如果某个服务部署了多个冗余的实例,客户端在向服务端发送请求时,根据负载均衡算法策略,请求可能会被转发到不同的服务提供者实例来处理,如何决定某个请求转发给哪个服务实例呢,最简单的做法就是轮询,顺次将请求转发给每个服务实例进行处理。也可以采用随机方式,或者根据实际硬件环境和业务场景设置特定算法。

二、模式类图

三、程序示例

  在下面的演示策略模式的代码示例中,我们模拟猜拳游戏——剪刀石头布,猜拳的策略有两种:如果这次猜拳赢了,则下次还出同样的手势。另一种策略就是根据以前的猜拳结果,选择胜率最高的一种手势。

1、Hand类:表示猜拳游戏中的手势,并非Strategy策略模式中的角色。

package com.designpattern.cn.strategypattern;public class Hand {    public static final int HANDVALUE_ROCK = 0; //表示石头    public static final int HANDVALUE_SCISSORS = 1; //表示剪刀    public static final int HANDVALUE_PEPER = 2; //表示布    private static final Hand[] hand = {            new Hand(HANDVALUE_ROCK),            new Hand(HANDVALUE_SCISSORS),            new Hand(HANDVALUE_PEPER)    };    private static final String[] name = {            "石头", "剪刀", "布"    };    private int handValue;    private Hand(int handValue){        this.handValue = handValue;    }    public static Hand getHand(int handValue){        return hand[handValue];    }    public boolean isStrongerThan(Hand h){        return  fight(h) == 1;    }    public boolean isWeakerThan(Hand h){        return fight(h) == -1;    }    private int fight(Hand h){        if(this == h) {            return 0;        }else if((this.handValue + 1)%3 == h.handValue){            return 1;        }else{            return -1;        }    }    public String toString(){        return name[handValue];    }}
View Code

2、Strategy接口:

package com.designpattern.cn.strategypattern;public interface Strategy {    public abstract Hand nextHand();    public abstract void study(boolean win);}
View Code

3、WinningStrategy类:

package com.designpattern.cn.strategypattern;import java.util.Random;public class WinningStrategy implements Strategy {    private Random random;    private  boolean won = false; //上一局的输赢结果    private  Hand prevHand; //上一局的手势    public WinningStrategy(int seed){        random = new Random(seed);    }    public Hand nextHand(){        if(!won){            prevHand = Hand.getHand(random.nextInt(3));        }        return prevHand;    }    public void study(boolean win){        won = win;    }}
View Code

4、ProbStrategy类:

package com.designpattern.cn.strategypattern;import java.util.Random;public class ProbStrategy implements Strategy {    private Random random;    private int prevHandValue = 0;    private int currentHandValue = 0;    //history[上一局的手势][这一局的手势] 表达式的值越高表示过去的胜率越高    //study方法会根据nextHand方法返回的手势胜负结果更新history字段中的值    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][1]){ handValue = 1; }else{ handValue = 2; } prevHandValue = currentHandValue; currentHandValue = handValue; return Hand.getHand(handValue); } private int getSum(int hv){ int sum = 0; for (int i : history[hv] ) { sum += i; } return sum; } public void study(boolean win){ if(win){ history[prevHandValue][currentHandValue]++; }else{ history[prevHandValue][(currentHandValue+1)%3]++; history[prevHandValue][(currentHandValue+2)%3]++; } }}
View Code

5、Player类:

package com.designpattern.cn.strategypattern;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++;    }    public String toString(){        return "[" + name + ":" + gamecount + " games, " + wincount +                " win, " + losecount + " lose" + "]";    }}
View Code

6、Main类与运行结果:

package com.designpattern.cn.strategypattern;import java.util.Random;public class Main {    public static void main(String[] args){        int seed1 = ((new Random()).nextInt(500))*(1+(new Random()).nextInt(500));        int seed2 = seed1 * (new Random()).nextInt(500);        Player player1 = new Player("Taro", new WinningStrategy(seed1));        Player player2 = new Player("Hana", new ProbStrategy(seed2));        for(int i = 0; i < 100000; 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: " + player2);                player2.win();                player1.lose();            }else{                System.out.println("Even...");                player1.even();                player2.even();            }        }        System.out.println("Total result:");        System.out.println(player1.toString());        System.out.println(player2.toString());    }}
View Code

四、Strategy策略模式中的角色

  • Strategy策略:负责定义实现策略必须的接口方法
  • ConcreteStrategy具体的策略:实现Strategy角色的接口,如程序中的WinningStrategy和ProbStrategy
  • Context上下文:负责使用Strategy策略,如示例程序中的player。

五、相关的设计模式

  • Flyweight享元模式:通过使用享元模式,让多个地方共用ConcreteStrategy角色;
  • Abstract Factory抽象工厂:策略模式整体替换算法,抽象工厂整体替换具体的工厂,零件和产品;
  • State状态模式:状态模式和策略模式都可以替换被委托对象,而且类之间的关系也相似,只是两种模式目的不同。strategy策略模式替换被委托对象的类;状态模式中,每次状态发生变化时,被委托的对象必定会被替换。

 

转载于:https://www.cnblogs.com/zheng-hong-bo/p/11109383.html

你可能感兴趣的文章
hdu 5726
查看>>
正则表达式
查看>>
(BFS)poj2935-Basic Wall Maze
查看>>
BZOJ3879: SvT
查看>>
GO语言学习——LiteIDE
查看>>
PHP+MySQL中字符集问题分析
查看>>
java的反射机制和javassist、asm
查看>>
imageNamed 、imageWithContentsOfFile、 initWithContentsFile区别
查看>>
【转】TCP/IP详解学习笔记(二)
查看>>
x or y.若X为真返回X
查看>>
大数据 — Yarn
查看>>
datagridview,第一列前没有灰的一列
查看>>
根据开始字符串和结束字符串截取文件生成另一个文件(日志处理)【我】
查看>>
C# Lambda 表达式 (小记)
查看>>
关于有默认值的字段在用EF做插入操作时的思考
查看>>
call、apply、bind用法
查看>>
常用排序算法二
查看>>
兼容性问题
查看>>
Keepalived详细介绍简介
查看>>
2014-07-24 .NET实现微信公众号的消息回复与自定义菜单
查看>>