一、模式说明

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

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

二、模式类图

三、程序示例

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

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];
}
}

2、Strategy接口:

package com.designpattern.cn.strategypattern;

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

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;
}
}

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]++;
}
}
}

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" + "]";
}
}

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());
}
}

四、Strategy策略模式中的角色

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

五、相关的设计模式

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

一天一个设计模式——Strategy策略模式的更多相关文章

  1. Java的设计模式----strategy(策略模式)

    设计模式: 一个程序员对设计模式的理解: “不懂”为什么要把很简单的东西搞得那么复杂.后来随着软件开发经验的增加才开始明白我所看到的“复杂”恰恰就是设计模式的精髓所在,我所理解的“简单”就是一把钥匙开 ...

  2. C++设计模式-Strategy策略模式

    Strategy策略模式作用:定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户. UML图: Strategy模式将逻辑(算法)封装到一个类(Cont ...

  3. Java设计模式---Strategy策略模式

    参考于 : 大话设计模式 马士兵设计模式视频 1.场景介绍 购物网站上有一个产品,有三个字段,档次,价格,重量. 有些同学喜欢轻的,有些手头紧,想要便宜的,有些喜欢档次高的. 那么我们为了提高网站用户 ...

  4. [C++设计模式] strategy 策略模式

    依照陈硕老师的观点.c++里有面向过程编程.面向对象编程,基于对象编程(面向接口编程)和泛型编程.四种思路都各有其适用场景. 面向过程编程是沿袭C的结构化编程思路,OOP是C++的核心,也是现代高级编 ...

  5. 设计模式:Strategy 策略模式 -- 行为型

    设计模式 策略模式Strategy(对象行为型) 这是几年前写的文字(转载做的笔记更准确些),发觉还是废话多了点. 其实,核心就是5.结构中的UML图 5.1 和 5.2(新增).现在看这张图就觉得一 ...

  6. 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)

    原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...

  7. 设计模式22:Strategy 策略模式(行为型模式)

    Strategy 策略模式(行为型模式) 动机(Motivation) 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂:而且有时候支持 ...

  8. 设计模式之策略模式和状态模式(strategy pattern & state pattern)

    本文来讲解一下两个结构比较相似的行为设计模式:策略模式和状态模式.两者单独的理解和学习都是比较直观简单的,但是实际使用的时候却并不好实践,算是易学难用的设计模式吧.这也是把两者放在一起介绍的原因,经过 ...

  9. 设计模式:策略模式(Strategy)

    定   义:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化, 不会影响到使用算法的客户. 示例:商场收银系统,实现正常收费.满300返100.打8折.......等不同收费 ...

随机推荐

  1. ubuntu 环境下pycharm的 安装与激活教程

    1. 基本安装: 1.1 打开Ubuntu的应用市场,并在搜索栏搜索pycharm,结果如下图所示 1.2 选择pro版本进行安装,结果如下图所示: 1.3打开安装后的pycharm,如果出现下图所示 ...

  2. Python基础week2

    本节内容 列表.元组操作 字符串操作 字典操作 集合操作 文件操作 字符编码与转码 1. 列表.元组操作 列表是我们最以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 定义列表 ...

  3. springboot启动不能加载数据库驱动Failed to determine a suitable driver class

    SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/G:/sharp/repo ...

  4. 002-var_dump用法

    <?php $a = 2150; //小刘的工资2150 $b = 2240; //小李的工资2240 echo "a=" . $a . "  b=" . ...

  5. JS在不改变原数组的情况下复制一个新的数组

    var a={1,2,3,4} var data= JSON.parse(JSON.stringify(a[0])) a.push(data) a[4]=5 这样就不会改变原数组a的数据

  6. ACM-挑战题之排列生成

    题目描述:挑战题之排列生成 一自然数N,设N为3,则关于N的字典序排列为123,132,213,231,312,321.对于一个自然数N(1<= N <= 9 ) , 你要做的便是生成它的 ...

  7. 锤子科技向OpenBSD基金会捐款195 万

    导读 专注于提供 OpenBSD 资讯的网站 OpenBSD Journal 昨日报道了锤子科技成为 OpenBSD 基金会 2019 年首位铱金捐赠者的消息. 根据 OpenBSD Journal ...

  8. WebStorm 使用经验

        1.优点 1.1 可自动提示图片的宽高 1.2 标签名字可重构(改名) 1.3 css重命名 1.4 可把内联的style移到外部 1.5 可实现声明提升 1.6 设置项是可搜索的 1.7 有 ...

  9. Rabbitmq之高级特性——百分百投递消息&消息确认模式&消息返回模式实现

    rabbitmq的高级特性: 如何保障消息的百分之百成功? 要满足4个条件:生产方发送出去,消费方接受到消息,发送方接收到消费者的确认信息,完善的消费补偿机制 解决方案,1)消息落库,进行消息状态打标 ...

  10. 集成模拟温度传感器低成本2.4G CC2500RGPR 中文手册

    CC2500是一种低成本真正单片的2.4GHz收发器,为低功耗无线应用而设计.电路定位2400-2483.5MHz的ISM(工业,科学和医学)和SRD(短距离设备)频率波段. RF收发器集成了一个数据 ...