当前位置: 首页 > news >正文

十三、行为型(策略模式)

策略模式(Strategy Pattern)

概念
策略模式(Strategy Pattern)是一种行为型设计模式,允许定义一系列算法,将每个算法封装在策略类中,并使它们可以互换使用。客户端可以根据需要动态选择不同的策略对象,从而在运行时决定采用哪种具体算法。


应用场景

  1. 算法的可替换性:当系统有多个不同的算法且这些算法可以互相替换时,可以使用策略模式。例如,排序算法、压缩算法等不同算法的实现。

  2. 避免条件分支:当系统中存在大量的if-elseswitch-case语句以选择不同的算法或行为时,可以使用策略模式将这些条件分支移入不同的策略类中,减少代码复杂度。

  3. 动态地选择行为:策略模式允许在运行时动态地选择或切换不同的算法或行为。例如,支付系统中可以选择不同的支付方式(如信用卡、支付宝、微信等)作为策略。

  4. 解耦行为与使用者:策略模式使得具体的算法实现与使用算法的类解耦,使用者无需了解具体的算法实现,只需使用策略接口即可。


注意点

  • 策略的数量:随着算法或行为的增加,策略类的数量也会增加,可能会造成类数量的膨胀。
  • 策略的独立性:策略类应当是独立的,相互之间不应依赖。如果策略之间有逻辑关系,可能需要进一步重构。
  • 客户端必须知晓策略:客户端需要了解并决定使用哪种策略,可能增加其复杂度。

核心要素

  1. Strategy(策略接口):定义一系列可供选择的算法或行为。
  2. ConcreteStrategy(具体策略):具体的算法实现类,每个策略类实现不同的算法。
  3. Context(上下文类):维护一个策略对象,并根据客户端的选择动态使用不同的策略。

Java代码完整示例

代码示例:简单策略模式

// 定义策略接口
interface Strategy {void execute();
}// 具体策略类 A
class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("使用策略A进行操作");}
}// 具体策略类 B
class ConcreteStrategyB implements Strategy {@Overridepublic void execute() {System.out.println("使用策略B进行操作");}
}// 上下文类,维护一个策略对象
class Context {private Strategy strategy;// 构造函数注入策略对象public Context(Strategy strategy) {this.strategy = strategy;}// 动态设置策略public void setStrategy(Strategy strategy) {this.strategy = strategy;}// 执行策略public void executeStrategy() {strategy.execute();}
}// 客户端代码
public class StrategyPatternDemo {public static void main(String[] args) {// 使用策略AContext context = new Context(new ConcreteStrategyA());context.executeStrategy();// 切换到策略Bcontext.setStrategy(new ConcreteStrategyB());context.executeStrategy();}
}

输出结果

使用策略A进行操作
使用策略B进行操作

各种变形用法完整示例

  1. 策略模式结合枚举
    通过枚举来实现策略模式,每个枚举实例代表一种策略。

    代码示例

    enum PaymentStrategy {CREDIT_CARD {@Overridepublic void pay(double amount) {System.out.println("使用信用卡支付: " + amount + " 元");}},PAYPAL {@Overridepublic void pay(double amount) {System.out.println("使用PayPal支付: " + amount + " 元");}},ALIPAY {@Overridepublic void pay(double amount) {System.out.println("使用支付宝支付: " + amount + " 元");}};public abstract void pay(double amount);
    }public class PaymentContext {private PaymentStrategy strategy;public PaymentContext(PaymentStrategy strategy) {this.strategy = strategy;}public void setStrategy(PaymentStrategy strategy) {this.strategy = strategy;}public void pay(double amount) {strategy.pay(amount);}public static void main(String[] args) {PaymentContext context = new PaymentContext(PaymentStrategy.CREDIT_CARD);context.pay(100.0);context.setStrategy(PaymentStrategy.PAYPAL);context.pay(200.0);context.setStrategy(PaymentStrategy.ALIPAY);context.pay(300.0);}
    }
    

    输出结果

    使用信用卡支付: 100.0 元
    使用PayPal支付: 200.0 元
    使用支付宝支付: 300.0 元
    
  2. 策略模式结合Lambda表达式
    在Java 8中,可以使用Lambda表达式简化策略模式的实现,将策略作为函数式接口来处理。

    代码示例

    interface Strategy {void execute();
    }public class StrategyLambdaDemo {public static void main(String[] args) {// 使用Lambda表达式定义不同策略Strategy strategyA = () -> System.out.println("使用策略A执行操作");Strategy strategyB = () -> System.out.println("使用策略B执行操作");// 创建上下文并设置策略Context context = new Context(strategyA);context.executeStrategy();context.setStrategy(strategyB);context.executeStrategy();}
    }
    

    输出结果

    使用策略A执行操作
    使用策略B执行操作
    
  3. 策略模式结合工厂模式
    可以通过工厂模式来创建不同的策略对象,并根据条件动态选择合适的策略。

    代码示例

    // 定义策略接口
    interface Strategy {void execute();
    }// 具体策略类 A
    class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("使用策略A进行操作");}
    }// 具体策略类 B
    class ConcreteStrategyB implements Strategy {@Overridepublic void execute() {System.out.println("使用策略B进行操作");}
    }// 策略工厂类
    class StrategyFactory {public static Strategy getStrategy(String type) {switch (type) {case "A":return new ConcreteStrategyA();case "B":return new ConcreteStrategyB();default:throw new IllegalArgumentException("未知策略类型");}}
    }// 上下文类
    class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public void executeStrategy() {strategy.execute();}
    }// 客户端
    public class StrategyFactoryDemo {public static void main(String[] args) {// 通过工厂创建策略对象Context context = new Context(StrategyFactory.getStrategy("A"));context.executeStrategy();context = new Context(StrategyFactory.getStrategy("B"));context.executeStrategy();}
    }
    

    输出结果

    使用策略A进行操作
    使用策略B进行操作
    
  4. 策略模式结合依赖注入
    使用依赖注入框架(如Spring)动态选择策略,这样可以将策略的选择交给框架来管理。

    代码示例(伪代码)

    // 定义策略接口
    interface Strategy {void execute();
    }// 具体策略类 A
    @Component("strategyA")
    class ConcreteStrategyA implements Strategy {@Overridepublic void execute() {System.out.println("使用策略A进行操作");}
    }// 具体策略类 B
    @Component("strategyB")
    class ConcreteStrategyB implements Strategy {@Overridepublic void execute() {System.out.println("使用策略B进行操作");}
    }// 上下文类
    @Component
    class Context {private final Map<String, Strategy> strategies;// 使用Spring自动注入策略Mappublic Context(Map<String, Strategy> strategies) {this.strategies = strategies;}public void executeStrategy(String strategyType) {Strategy strategy = strategies.get(strategyType);if (strategy != null) {strategy.execute();} else {throw new IllegalArgumentException("未知策略类型");}}
    }// 客户端
    @SpringBootApplication
    public class StrategySpringDemo {public static void main(String[] args) {ApplicationContext context = SpringApplication.run(StrategySpringDemo.class, args);Context strategyContext = context.getBean(Context.class);strategyContext.executeStrategy("strategyA");strategyContext.executeStrategy("strategyB");}
    }
    

    输出结果

    使用策略A进行操作
    使用策略B进行操作
    

通过这些不同的变形,策略模式不仅能应对多种不同的需求场景,还能与现代开发方法(如枚举、Lambda、工厂模式、依赖注入等)灵活结合,进一步提升代码的可维护性和可扩展性。

相关文章:

十三、行为型(策略模式)

策略模式&#xff08;Strategy Pattern&#xff09; 概念 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;允许定义一系列算法&#xff0c;将每个算法封装在策略类中&#xff0c;并使它们可以互换使用。客户端可以根据需要动态选择不同的策…...

Vue环境安装以及配置

这里写目录标题 前言一、前置要求1.安装Node.js2. 安装VScode 二、创建全局安装目录和缓存日志目录三、配置环境变量四、权限五、npm换源六、vscode插件1. Vue-Offical2. Vue 3 Snippets3. Path Intellisense4. Auto Import5. Auto Close Tag6. Auto Rename Tag7.GitLens总结 前…...

Redis 数据类型hash(哈希)

目录 1 基本特性 2 主要操作命令 2.1 设置和获取字段 2.1.1 HSET key field value 2.1.2 HGET key field 2.1.3 HMSET key field1 value1 [field2 value2 ...] 2.1.4 HMGET key field1 [field2 ...] 2.2 检查字段是否存在 2.2.1 HEXISTS key field 2.3 获取所有字段…...

单一执行和循环执行的例行性工作

单一执行的例行性工作&#xff1a;只执行一次就结束 1.1at命令的工作过程 /etc/at.allow&#xff0c;写在该文件的人可以使用at命令 /etc/at.deny&#xff0c;黑名单 两个文件如果都不存在&#xff0c;只有root能使用 [rootlocalhost ~]# systemctl status atd [rootlocalh…...

单细胞分析 | Cicero+Signac 寻找顺式共可及网络

引言 在本指南[1]中&#xff0c;将介绍如何利用Cicero工具和单细胞ATAC-seq数据来识别共可接近网络。 为了在Seurat&#xff08;Signac工具使用的格式&#xff09;和CellDataSet&#xff08;Cicero工具使用的格式&#xff09;之间轻松转换数据&#xff0c;将利用GitHub上的Seur…...

人工智能创造出大量新型蛋白质

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

Palo Alto Networks Expedition 未授权SQL注入漏洞复现(CVE-2024-9465)

0x01 产品介绍&#xff1a; Palo Alto Networks Expedition 是一款强大的工具&#xff0c;帮助用户有效地迁移和优化网络安全策略&#xff0c;提升安全管理的效率和效果。它的自动化功能、策略分析和可视化报告使其在网络安全领域中成为一个重要的解决方案。 0x02 漏洞描述&am…...

c 语言 sprintf

在C语言中&#xff0c;sprintf是一个非常常用的函数&#xff0c;它用于将格式化的数据写入字符串中。sprintf函数的原型通常定义在stdio.h头文件中。 sprintf函数的原型如下&#xff1a; int sprintf(char *str, const char *format, …); 参数说明&#xff1a; str&#xf…...

stm32单片机个人学习笔记10(TIM编码器接口)

前言 本篇文章属于stm32单片机&#xff08;以下简称单片机&#xff09;的学习笔记&#xff0c;来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记&#xff0c;只能做参考&#xff0c;细节方面建议观看视频&#xff0c;肯定受益匪浅。 STM32入门教程-2023版 细…...

如何在Android中存储数据?

在Android中存储数据是开发过程中至关重要的一环&#xff0c;根据数据的类型、大小、访问频率及安全性需求&#xff0c;开发者可以选择多种存储方式。以下是Android中存储数据的几种主要方式&#xff0c;每种方式都有其特定的应用场景和优缺点。 一、SharedPreferences Share…...

13.3寸工业三防平板数字化工厂产线数采手持终端

在数字化工厂的建设浪潮中&#xff0c;高效可靠的数据采集终端至关重要。尤其在水处理、食品加工等特殊工业环境下&#xff0c;设备的耐用性和数据安全性面临严峻挑战。传统的平板电脑难以应对复杂的工业现场&#xff0c;而一款性能卓越、坚固耐用的工业三防平板则成为提升生产…...

ssh连接慢的问题或zookeeper远程连接服务超时

问题原因&#xff1a; 在SSH登录过程中&#xff0c;服务器会通过反向DNS查找客户端的主机名&#xff0c;然后与登录的IP地址进行匹配&#xff0c;以验证登录的合法性。如果客户端的IP没有域名或DNS服务器响应缓慢&#xff0c;这可能导致SSH登录过慢。为了解决这个问题&#xf…...

perf工具使用指导

linux perf工具使用指导 perf 是 Linux 内核自带的性能分析工具&#xff0c;主要用于分析系统性能瓶颈和程序的性能问题。通过合理使用 perf 工具&#xff0c;可以有效地分析和优化系统性能。 安装 perf 在大多数 Linux 发行版中&#xff0c;perf 工具通常随内核源代码包一起…...

WordPress 禁用上传媒体图片自动生成缩略图及多尺寸图片教程

一、在 设置-媒体-媒体设置 中几个尺寸大小的设置不勾选或设置为 0&#xff0c;如下图&#xff1a; 二、找到主题文件 function.php 文件&#xff0c;打开后&#xff0c;在 <?php 后面添加如下代码&#xff1a; function.php 文件路径一般为&#xff1a;WordPress网站根目录…...

锥线性规划【分布鲁棒、两阶段鲁棒方向知识点】

1 锥线性对偶理论 本部分看似和分布鲁棒、两阶段鲁棒优化没什么关系&#xff0c;但值得优先学习&#xff0c;原因将在最后揭晓。 二阶锥 二阶锥&#xff08;second-order cone&#xff0c;又称ice-cream/Lorentz cone&#xff09;的形式为&#xff1a; 非负象限锥 半正定锥 …...

linux环境下的程序设计与git操作

目录 前言&#xff1a; 进度条小程序&#xff1a; 先介绍几个背景知识 代码实现 Git操作 总结 其他指令 前言&#xff1a; 本文将重点介绍1. linux下的程序设计&#xff0c;并使用linux下的几个函数接口。实现一个简单的小程序 2.本着开源精神&#xff0c;进行git操作。…...

Matlab中HybridFcn参数的用法

在 MATLAB 中&#xff0c;HybridFcn 参数允许你在全局优化&#xff08;如遗传算法 ga 或粒子群算法 particleswarm&#xff09;之后使用局部优化算法进一步微调解的精确度。HybridFcn 通过在全局优化找到的解基础上&#xff0c;进一步调用局部优化器&#xff0c;如 fmincon、pa…...

Leetcode 3316. Find Maximum Removals From Source String

Leetcode 3316. Find Maximum Removals From Source String 1. 解题思路2. 代码实现 题目链接&#xff1a;3316. Find Maximum Removals From Source String 1. 解题思路 这一题思路上的话就是一个动态规划的题目&#xff0c;我们仿照lcs&#xff0c;考察每一个位置是否可以…...

jeecg3版本的vue,离线启动

jeecg的vue2版本已经停止维护&#xff0c;所以只能用vue3的版本。3版本中使用的是pnpm&#xff08;npm的增强版本&#xff09;下载依赖。使用pnpm安装的node_modules&#xff0c;不能直接复制到离线主机中&#xff08;因为在 pnpm安装过程中&#xff0c;会给依赖的配置文件写死…...

C++的内存管理

[TOC} C的内存管理 各个区储存内容 1.栈 局部变量和在执行函数时&#xff0c;函数中创建的局部变量都会在栈上创建&#xff0c;函数执行结束时会被自动释放。从高地址向低地址储存。 2.堆 是new/malloc/calloc/realloc分配的代码块&#xff0c;需要手动释放。如果程序员没…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...

MySQL:分区的基本使用

目录 一、什么是分区二、有什么作用三、分类四、创建分区五、删除分区 一、什么是分区 MySQL 分区&#xff08;Partitioning&#xff09;是一种将单张表的数据逻辑上拆分成多个物理部分的技术。这些物理部分&#xff08;分区&#xff09;可以独立存储、管理和优化&#xff0c;…...