【设计模式-行为型】策略模式

devtools/2025/1/21 7:19:46/

一、什么是策略模式

        要说策略模式,那么我脑袋里有一个例子,是一个策略模式使用的大家,那就是在周星驰的电影《国产凌凌漆》中的----达文西。

        达文西:“没错就是我,请叫我文西”。

        电影中,角色达文西以其机智和创造力,生动地展示了策略模式的精髓。面对电影中的反派角色金枪客的威胁,达文西,这位“聪明的发明家”,迅速设计并制造了一种应对紧急情况的策略武器——“要你命3000”。

        “要你命3000”是一种超级武器,它巧妙地将西瓜刀、铁链、火药、硫酸、毒药、手枪、手榴弹等十多种武器结合在一起,形成了一种看似强大但实际上荒谬的混合武器。达文西在剧中自豪地介绍他的发明:“要你命三千,西瓜刀,铁链,火药,硫酸,毒药,手枪,手榴弹,杀虫剂,每样都能独当一面,现在集中在一起,看你怕不怕?”这句话不仅展现了达文西的幽默感,也体现了策略模式的核心思想:通过组合不同的元素来应对特定的挑战。

        这个场景中的“要你命3000”就是策略模式的一个典型应用。策略模式允许我们在运行时根据不同的情况选择不同的算法或行为,就像达文西根据不同的威胁选择不同的武器一样。这种模式使得系统更加灵活,能够适应不断变化的需求。

策略模式的定义策略模式是一种行为设计模式,它定义了一系列算法(要你命3000),将每个算法封装起来(要你命3000中的每个武器),并使它们可以互换(可以使用每种武器应对金枪客)。

二、为什么用策略模式

那么我们可以根据这个示例,来讨论一下为什么要使用策略模式(为啥会想到用要你命3000):

  1. 算法多样性:在电影中,达文西面对不同的敌人和战斗场景,需要不同的武器。这就像在软件开发中,我们可能需要根据不同的输入或条件来选择不同的算法。策略模式允许我们在运行时选择最合适的算法。例子: 假设我们有一个支付系统,需要支持多种支付方式(现金、信用卡、移动支付等)。每种支付方式都是一个策略。通过策略模式,我们可以轻松地添加新的支付方式,而不需要修改现有的代码。

  2.  代码复用:达文西的“要你命3000”虽然是一个荒谬的发明,但它展示了如何将不同的工具组合起来以应对特定的挑战。在软件开发中,这意味着我们可以重用已有的算法,而不需要每次都重新编写代码。例子: 在图像处理软件中,我们可能有多种图像滤镜(如模糊、锐化、边缘检测等)。每种滤镜都是一个策略。通过策略模式,我们可以在不同的上下文中重用这些滤镜算法,而不需要为每个新功能重新编写代码。

  3. 简化切换:在电影中,达文西可能需要快速地从一种武器切换到另一种武器。在软件开发中,策略模式允许我们在运行时轻松地切换算法,而不需要复杂的条件判断。例子: 在游戏开发中,我们可能需要根据玩家的选择或游戏状态来切换不同的AI行为。通过策略模式,我们可以轻松地在不同的AI策略之间切换,以适应游戏的不同阶段或玩家的不同行为。

  4.  提高可读性:达文西的发明虽然荒诞,但它清晰地展示了如何将不同的元素组合起来。在软件开发中,策略模式通过将算法封装在独立的类中,提高了代码的可读性和可理解性。例子: 在文本编辑器中,我们可能有多种文本格式化策略(如加粗、斜体、下划线等)。通过策略模式,我们可以清晰地定义每种格式化策略,使得代码更加模块化和易于理解。

  5. 易于扩展:达文西的“要你命3000”展示了如何通过组合不同的元素来创造新的发明。在软件开发中,策略模式使得添加新的算法变得非常容易,而不需要修改现有的代码。例子: 在电子商务平台中,我们可能需要支持多种配送策略(如快递、平邮、同城配送等)。通过策略模式,我们可以轻松地添加新的配送策略,而不需要修改现有的订单处理代码。

  6. 解耦:达文西的发明展示了如何将不同的元素组合起来,而不需要它们之间有直接的依赖关系。在软件开发中,策略模式将算法的实现与使用算法的客户端解耦,提高了系统的灵活性。例子: 在数据库访问层中,我们可能需要支持多种数据库操作(如查询、更新、删除等)。通过策略模式,我们可以将数据库操作的实现与使用这些操作的业务逻辑解耦,使得数据库访问层更加灵活和可维护。

三、策略模式示例

        在代码中,我一般很少直接用策略模式,一般直接使用策略枚举:

  1. 武器策略接口(约束算法的行为):
    //武器策略接口
    public interface WeaponStrategy {void attack();
    }
  2. 武器的实现类(具体的算法):
    //西瓜刀武器策略
    public class WatermelonKnifeStrategy implements WeaponStrategy {@Overridepublic void attack() {System.out.println("吃我一西瓜刀!");}
    }
    //链条武器策略
    public class ChainStrategy implements WeaponStrategy {@Overridepublic void attack() {System.out.println("吃我一链条!");}
    }
    //火药武器策略
    public class GunpowderStrategy implements WeaponStrategy {@Overridepublic void attack() {System.out.println("吃我一火药!");}
    }
  3. 武器组合(要你命3000):
    //武器库:枚举
    public enum BattleStrategyEnum {WATERMELON_KNIFE("watermelon_knife", new WatermelonKnifeStrategy()),CHAIN("chain", new ChainStrategy()),GUNPOWDER("gunpowder", new GunpowderStrategy());private final String key;private final WeaponStrategy strategy;BattleStrategyEnum(String key, WeaponStrategy strategy) {this.key = key;this.strategy = strategy;}public String getKey() {return key;}public WeaponStrategy getStrategy() {return strategy;}public static WeaponStrategy getStrategyByKey(String key) {for (BattleStrategyEnum strategy : BattleStrategyEnum.values()) {if (strategy.getKey().equals(key)) {return strategy.getStrategy();}}throw new IllegalArgumentException("No strategy found for key: " + key);}
    }
  4. 达文西使用场景(根据传入的不同策略,执行对应的策略):
    public class BattleContext {private WeaponStrategy strategy;public BattleContext(String strategyKey) {this.strategy = BattleStrategyEnum.getStrategyByKey(strategyKey);}public void executeStrategy() {strategy.use();}
    }
  5. 场景(达文西大战金枪客)
    public class BattleSimulation {public static void main(String[] args) {// 模拟战斗场景System.out.println("Battle against Golden Gunman starts:");// 创建上下文对象BattleContext context;// 初期战斗策略context = new BattleContext(BattleStrategyEnum.WATERMELON_KNIFE.getKey());System.out.println("吃我一招:");context.executeStrategy();// 中期战斗策略context = new BattleContext(BattleStrategyEnum.CHAIN.getKey());System.out.println("再来一招:");context.executeStrategy();// 最终战斗策略context = new BattleContext(BattleStrategyEnum.GUNPOWDER.getKey());System.out.println("最后一招:");context.executeStrategy();}
    }


http://www.ppmy.cn/devtools/152287.html

相关文章

matlab计算功率谱的四种方法

%{ 计算功率谱的四种方法,前三种方法采用归一化频率,第四种方法采用原始频率 %} clear;clc;close all; % 生成一个示例时间序列(例如正弦波加上一些随机噪声) t 0:0.01:100-0.1; % 时间向量 % x sin(t) 0.5 * randn(size(t))…

【opencv】第10章 角点检测

第10章 角点检测 10.1 Harris角点检测 10.1.1 兴趣点与角点 在图像处理和与计算机视觉领域,兴趣点(interest points),也被称作关键点 (key points)、特 征 点(feature points)。它被大量用于解决物体识别、图像识别、 图像匹配、视觉跟踪、三维重建等一系列的问题…

GoLang 微服务学习笔记

https://www.bilibili.com/video/BV1Gg4y1u77D/?spm_id_from333.337.search-card.all.click&vd_source707ec8983cc32e6e065d5496a7f79ee6 目录 第1讲:为什么说云原生重构了互联网产品开发模式? https://www.bilibili.com/video/BV1Gg4y1u77D?spm_i…

MySQL字符串函数详解

简介 本文主要讲解MySQL中的字符串函数,包括:left、right、ltrim、rtrim、trim、upper、lower、lpad、rpad、concat、concat_ws、instr、substr、length、char_length、replace、reverse、char、ascii。 left函数 语法:left(str,length)&a…

Kotlin 2.1.0 入门教程(三)

变量 在 Kotlin 中,可以通过关键字 val 或 var 声明变量,后跟变量名称。 使用 val 关键字声明只能赋值一次的变量。这些是不可变的、只读的局部变量,初始化后不能重新赋值。 fun main() {val a 1val b: Int 2println("a $a, b $b…

【STM32-学习笔记-8-】I2C通信

文章目录 I2C通信Ⅰ、硬件电路Ⅱ、IIC时序基本单元① 起始条件② 终止条件③ 发送一个字节④ 接收一个字节⑤ 发送应答⑥ 接收应答 Ⅲ、IIC时序① 指定地址写② 当前地址读③ 指定地址读 Ⅳ、MPU6050---6轴姿态传感器(软件I2C)1、模块内部电路2、寄存器地…

Java ArrayList

Java ArrayList 从名字就可以看得出来,ArrayList 实现了 List 接口,并且是基于数组实现的。 有人就会问了 那ArrayList和数组有什么区别呢 数组的大小是固定的,一旦创建的时候指定了大小,就不能再调整了。也就是说,…

1166 Summit (25)

A summit (峰会) is a meeting of heads of state or government. Arranging the rest areas for the summit is not a simple job. The ideal arrangement of one area is to invite those heads so that everyone is a direct friend of everyone. Now given a set of tenta…