Java二十三种设计模式-策略模式(13/23)

策略模式:灵活算法的替换与扩展

引言

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

基础知识,java设计模式总体来说设计模式分为三大类:

(1)创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

(2)结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

(3)行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

第一部分:策略模式概述

1.1 定义与用途

策略模式的基本定义

策略模式是一种行为型设计模式,它允许在运行时选择算法的行为,将算法封装在独立的策略类中,从而让算法可以互相替换。

解释为何需要策略模式

  • 算法的多样性:在许多应用中,可能需要根据不同的条件执行不同的算法或行为。
  • 算法的独立性:策略模式让算法独立于使用它们的客户端,使得算法可以独立变化和扩展。
  • 避免多重条件语句:使用策略模式可以避免在客户端代码中使用复杂的条件语句来决定使用哪个算法。

1.2 策略模式的组成

策略接口(Strategy Interface)

  • 定义:定义所有支持的算法的公共接口。
  • 角色:作为所有具体策略类的父接口,确保它们具有一致的方法签名。

具体策略(Concrete Strategy)

  • 定义:实现策略接口的具体算法类。
  • 角色:提供策略接口中定义的算法的具体实现。

上下文(Context)

  • 定义:使用策略接口与具体策略交互的类。
  • 角色:维持一个对策略对象的引用,并在运行时根据需要切换策略。

客户端(Client)

  • 角色:使用上下文对象来访问策略对象提供的服务。
  • 职责:客户端不直接与具体策略类交互,而是通过上下文来间接使用策略。

角色之间的交互

  • 客户端与上下文:客户端通过上下文来请求服务,上下文负责将请求委托给当前策略。
  • 上下文与具体策略:上下文通过内部的策略引用来调用具体策略的算法。

策略模式通过定义清晰的接口和角色,提供了一种灵活的方式来管理和使用不同的算法。在下一部分中,我们将通过Java代码示例来展示策略模式的具体实现。

第二部分:策略模式的实现

2.1 Java实现示例

以下是使用Java语言实现策略模式的代码示例。假设我们有一个简单的计算系统,需要根据不同的策略来执行加、减、乘、除操作。

// 策略接口
interface Strategy {int execute(int a, int b);
}// 具体策略:加法
class AddStrategy implements Strategy {public int execute(int a, int b) {return a + b;}
}// 具体策略:减法
class SubtractStrategy implements Strategy {public int execute(int a, int b) {return a - b;}
}// 上下文
class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy = strategy;}public void setStrategy(Strategy strategy) {this.strategy = strategy;}public int executeStrategy(int a, int b) {return strategy.execute(a, b);}
}// 客户端代码
public class Client {public static void main(String[] args) {Context context = new Context(new AddStrategy());System.out.println("Add: 10 + 5 = " + context.executeStrategy(10, 5));context.setStrategy(new SubtractStrategy());System.out.println("Subtract: 10 - 5 = " + context.executeStrategy(10, 5));}
}

 

2.2 策略模式中的角色和职责

策略接口(Strategy)

  • 职责:定义所有策略类必须遵循的公共接口,通常包含一个或多个执行算法的方法。

具体策略(Concrete Strategy)

  • 职责:实现策略接口,提供具体的算法实现。可以有多个具体策略类,每个类实现不同的算法。

上下文(Context)

  • 职责
    • 作为策略接口与具体策略的中介,存储对某个策略对象的引用。
    • 根据实际的策略对象来调用相应的算法方法。

客户端(Client)

  • 职责
    • 通过上下文来使用策略对象,不直接与具体策略类交互。
    • 可以根据需要通过上下文来切换不同的策略。

相互作用

  • 客户端与上下文:客户端创建上下文对象,并根据需要设置具体的策略对象。
  • 上下文与具体策略:上下文在执行操作时,委托给内部维护的策略对象来完成。
  • 客户端与具体策略:客户端不直接与具体策略交互,所有的交互都通过上下文来完成。

策略模式提供了一种灵活的方式来替换算法或行为,使得算法的变化独立于使用算法的客户。在下一部分中,我们将探讨策略模式的使用场景。

第三部分:策略模式的使用场景

3.1 需要替换算法或行为的场景

策略模式在需要根据不同条件替换算法或行为时非常有用。以下是一些具体的应用场景:

  • 用户自定义设置:在应用程序中,用户可能希望根据自己的偏好选择不同的排序或搜索算法。
  • 游戏AI:在游戏开发中,不同的敌人或角色可能使用不同的行为策略。
  • 支付方式:电子商务平台可能需要支持多种支付方式,如信用卡、PayPal、微信支付等。

策略模式的应用:

  • 条件分支的替代:使用策略模式可以替代大量的条件分支语句,使代码更加清晰。
  • 动态替换:策略模式允许在运行时根据条件动态替换算法,提高了系统的灵活性。

应用实例:

  • 文本编辑器:文本编辑器可能提供不同的文本格式化策略,如粗体、斜体、下划线等。

3.2 需要扩展新算法的场景

当系统需要扩展新算法时,策略模式提供了显著的优势,因为它允许开发者在不修改现有代码的基础上添加新的算法。

  • 无需修改现有代码:遵循开闭原则,对扩展开放,对修改封闭。
  • 算法的独立性:每个算法都是独立的类,可以独立开发和测试。

策略模式的优势:

  • 易于添加新策略:添加新策略时,只需实现策略接口并创建新的策略类。
  • 解耦算法与使用场景:策略模式将算法的实现与使用场景解耦,使得两者可以独立变化。

应用实例:

  • 图形渲染:图形渲染程序可能需要根据不同的对象类型使用不同的渲染策略,如点、线、多边形等。

通过策略模式,开发者可以在不同的场景下灵活地替换或扩展算法,同时保持代码的整洁和可维护性。在下一部分中,我们将讨论策略模式的优点与缺点。

第四部分:策略模式的优点与缺点

4.1 优点

提高灵活性

  • 动态替换:策略模式允许在运行时根据条件动态替换算法,提供了高度的灵活性。

增强可扩展性

  • 遵循开闭原则:遵循软件设计的开闭原则,对扩展开放,对修改封闭,便于添加新算法。

降低耦合度

  • 解耦算法与使用:将算法与使用算法的代码解耦,使得它们可以独立变化。

简化单元测试

  • 独立测试:由于算法的独立性,可以更容易地对策略进行单元测试。

易于维护和复用

  • 算法复用:相同的策略可以在不同的上下文中复用,减少了代码重复。

4.2 缺点

增加系统复杂性

  • 类的数量:策略模式可能会增加系统中类的数量,每个策略都需要一个独立的类。

增加设计难度

  • 理解难度:对于不熟悉策略模式的开发者,理解这种模式可能有一定难度。

性能考虑

  • 性能开销:在某些情况下,策略模式可能会引入额外的性能开销,尤其是在策略选择和委托过程中。

过度使用

  • 滥用风险:如果过度使用策略模式,可能会导致设计过度复杂化,例如,当算法差异很小或算法数量过多时。

策略管理

  • 策略选择:在策略数量很多的情况下,选择合适的策略可能变得复杂。

客户端负担

  • 客户端责任:客户端需要了解不同的策略并作出选择,这可能会增加客户端的负担。

策略模式是一种强大的设计模式,它通过将算法封装在独立的策略类中,提高了系统的灵活性和可扩展性。然而,合理使用策略模式并避免其缺点是至关重要的。了解其优点和缺点可以帮助开发者根据具体需求和场景选择最合适的设计模式。在实际开发中,应根据具体情况灵活运用策略模式,以达到最佳的设计效果。

第五部分:策略模式与其他模式的比较

5.1 与状态模式的比较

状态模式

  • 定义:状态模式允许一个对象在其内部状态改变时改变其行为,看起来好像改变了其类。
  • 使用场景:适用于对象状态较多且不同状态行为有明显差异的情况。

策略模式

  • 定义:策略模式定义了一系列算法,并将每一个算法封装起来,使它们可以互换。
  • 使用场景:适用于需要根据不同条件选择不同算法或策略的情况。

对比

  • 关注点:状态模式关注于对象状态的变化以及状态变化导致的行为变化,而策略模式关注于算法或策略的替换。
  • 使用目的:状态模式用于处理状态变化,策略模式用于处理算法的多样性和可替换性。

5.2 与命令模式的对比

命令模式

  • 定义:命令模式将请求或操作封装为一个对象,从而使你可以用不同的请求对客户进行参数化。
  • 使用场景:适用于需要将操作请求排队、记录、撤销或重做的情况。

策略模式

  • 定义:如上所述,策略模式用于定义算法族并使它们可以互换。

对比

  • 执行操作:命令模式关注于执行操作的封装和调度,策略模式关注于算法的替换和选择。
  • 使用目的:命令模式用于命令的封装和调用,策略模式用于算法的封装和使用。

其他区别

  • 组合使用:策略模式可以与命令模式结合使用,例如,将不同的策略作为命令的参数传递。
  • 职责分配:命令模式中的对象通常包含执行操作的所有信息,而策略模式将算法的实现与使用分离。

通过比较策略模式与状态模式和命令模式,我们可以更清晰地理解每种模式的独特用途和优势。在实际应用中,根据具体需求和场景选择合适的设计模式是非常重要的。在下一部分中,我们将提供策略模式的最佳实践和建议。

第六部分:策略模式的最佳实践和建议

6.1 最佳实践

保持策略接口的单一职责

  • 单一职责原则:确保策略接口只定义一个算法或行为,避免将多个不同的行为混合在一个接口中。

定义清晰的策略接口

  • 清晰的合同:策略接口应该清晰地定义策略的合同,让实现者容易理解和实现。

避免策略类的过度复杂

  • 简单实现:尽量保持策略类的实现简单,避免过度复杂的逻辑。

使用上下文封装策略逻辑

  • 封装变化:使用上下文类封装策略的逻辑,包括策略的选择和切换。

允许运行时策略替换

  • 动态行为:策略模式应该允许在运行时根据条件或用户输入替换策略。

提供默认策略

  • 默认实现:为避免在没有明确策略时出现错误,提供一个默认的策略实现。

6.2 避免滥用

避免策略类数量过多

  • 适度使用:避免因为过度使用策略模式而产生大量的策略类,这可能会使系统变得复杂和难以管理。

避免策略接口定义不当

  • 合理定义:确保策略接口的定义合理,既不要太宽泛也不要太狭窄。

避免忽视性能影响

  • 性能考量:在设计策略模式时,考虑策略选择和切换可能带来的性能影响。

6.3 替代方案

使用函数指针或函数引用

  • 简化实现:在某些编程语言中,可以使用函数指针或函数引用来简化策略模式的实现。

使用委托或回调

  • 回调机制:在不支持策略模式的环境下,可以使用委托或回调机制来达到类似的效果。

使用状态模式

  • 状态变化:当对象的状态变化需要改变其行为时,可以考虑使用状态模式。

使用组合模式

  • 部分-整体结构:当需要表示对象的部分-整体层次结构时,可以使用组合模式。

使用适配器模式

  • 接口适配:当需要将一个类的接口适配到另一个接口时,可以使用适配器模式。

策略模式是一种强大的设计模式,可以在运行时动态地替换算法或行为,提高了系统的灵活性和可扩展性。然而,合理使用策略模式并避免其缺点是至关重要的。了解其替代方案可以帮助开发者根据具体需求和场景选择最合适的设计模式。在实际开发中,应根据具体情况灵活运用策略模式,以达到最佳的设计效果。

结语

策略模式提供了一种灵活的方式来替换和扩展算法,使得系统更加灵活和可扩展。通过本文的深入分析,希望读者能够对策略模式有更全面的理解,并在实际开发中做出合理的设计选择。

 博主还写了其他Java设计模式关联文章,请各位大佬批评指正:

(一)创建型模式(5种):

Java二十三种设计模式-单例模式(1/23)

Java二十三种设计模式-工厂方法模式(2/23)

Java二十三种设计模式-抽象工厂模式(3/23)

Java二十三种设计模式-建造者模式(4/23)

Java二十三种设计模式-原型模式(5/23)

(二)结构型模式(7种): 

Java二十三种设计模式-适配器模式(6/23)

Java二十三种设计模式-装饰器模式(7/23)

Java二十三种设计模式-代理模式(8/23)

Java二十三种设计模式-外观模式(9/23)

Java二十三种设计模式-桥接模式(10/23)

Java二十三种设计模式-组合模式(11/23)

Java二十三种设计模式-享元模式(12/23)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/397117.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#小结:如何在VS2022中使用菜单栏中的Git管理代码

目录 第一部分:基础操作 第一步,登录官网,设置好邮箱,然后右上角新建仓库 第二步,提交代码到远程仓库中 第三步,查看和比对自己修改的内容 第四步,查看该项目所有提交历史记录 第五步&…

嵌入式人工智能(OpenCV-基于树莓派的人脸识别与入侵检测)

1、人脸识别 人脸识别是一种技术,通过检测、跟踪和识别人脸上的关键特征,以确认人脸的身份。它通常用于安保系统、身份验证、社交媒体和人机交互等领域。 人脸识别技术的基本原理是先通过图像处理和计算机视觉算法,提取人脸的特征点和特征描…

【ML】Pre-trained Language Models及其各种微调模型的实现细节和特点

Pre-trained Language Models及其各种微调模型的实现细节和特点 1. Pre-trained Language Models2. semi-supervised Learning3. zero-shot4. Parameter-Efficient Fine-Tuning4.1 含义:4.2 实现方式: 5. LoRA5.1 LoRA 的主要特点:5.2 LoRA 的…

Pytorch人体姿态骨架生成图像

ControlNet是一个稳定扩散模型,可以复制构图和人体姿势。ControlNet解决了生成想要的确切姿势困难的问题。 Human Pose使用OpenPose检测关键点,如头部、肩膀、手的位置等。它适用于复制人类姿势,但不适用于其他细节,如服装、发型和…

Linux中apache服务安装与mysql安装

目录 一、apache安装 二、MySQL安装 一、apache安装 准备环境:一台虚拟机、三个安装包(apr-1.6.2.tar.gz、apr-util-1.6.0.tar.gz、httpd-2.4.29.tar.bz2) 安装过程: tar xf apr-1.6.2.tar.gz tar xf apr-util-1.6.0.tar.gz tar xf http…

Burp Suite的使用和文件上传漏洞靶场试验

第一步:分析如何利用漏洞,通过对代码的查阅发现,代码的逻辑是先上传后删除,意味着,我可以利用webshell.php文件在上传到删除之间的间隙,执行webshell.php的代码,给上级目录创建一个shell.php木马…

IDEA右键新建时没有Java Class选项

项目场景: IDEA右键新建时没有Java Class选项 问题描述 IDEA右键新建时没有Java Class选项 原因分析: 提示:这里填写问题的分析: 例如:Handler 发送消息有两种方式,分别是 Handler.obtainMessage()和 Ha…

【扒代码】ope.py

文件目录: 引用方式 if not self.zero_shot: # 非零样本情况下,计算边界框的宽度和高度 box_hw torch.zeros(bboxes.size(0), bboxes.size(1), 2).to(bboxes.device) box_hw[:, :, 0] bboxes[:, :, 2] - bboxes[:, :, 0] # 宽度 box_hw[:, :, 1] bbox…

Docker in 100 Seconds

Docker a tool that can package software into containers that run reliably in any environment, but what is a container and why do you need one? Let’s imagine you built up an app with cobalt that runs some weird flavor of Linux. You want to share this app…

idea中好用的插件

输入法自动切换插件 自动切换输入法插件:Smart Input。编写代码时自动切换到英文输入法,注释代码自动切换为中文输入法。极大的提升我们的编码效率。 MyBatisX插件 MybatisX 是一款基于 IDEA 的快速开发插件,为效率而生。主要用于XML映射配…

吴恩达机器学习COURSE2 WEEK2

COURSE2 WEEK2 模型训练的细节 定义模型,即指定如何在给定输入特征 x x x 以及参数 w w w 和 b b b 的情况下计算输出 指定损失函数 L ( f w ⃗ , b ( x ⃗ ) , y ) L(f_{\vec w, b}(\vec x),y) L(fw ,b​(x ),y) 指定成本函数 J ( w ⃗ , b ) 1 m ∑ i 1 …

Linux系统驱动(十三)Linux内核定时器

文章目录 一、内核定时器原理二、定时器API三、使用定时器让LED灯闪烁四、使用定时器对按键进行消抖 一、内核定时器原理 内核当前时间通过jiffies获取,它是内核时钟节拍数,在linux内核启动的时候,jiffies开始(按照一定频率&…

【数据结构】顺序结构实现:特殊完全二叉树(堆)+堆排序

二叉树 一.二叉树的顺序结构二.堆的概念及结构三.堆的实现1.堆的结构2.堆的初始化、销毁、打印、判空3.堆中的值交换4.堆顶元素5.堆向上调整算法:实现小堆的插入6.堆向下调整算法:实现小堆的删除7.堆的创建1.堆向上调整算法:建堆建堆的时间复…

CentOS 安装Redis

在 CentOS 安装 Redis 操作系统:centos-7.9.2009-Core 1. 更新系统 首先,确保你的系统是最新的: sudo yum update -y2. 安装 EPEL 仓库 Redis 可能不在默认的 CentOS 仓库中,因此你需要安装 EPEL(Extra Packages f…

TCP详解及其在音视频传输中的应用

传输控制协议(TCP,Transmission Control Protocol)是互联网协议栈中至关重要的传输层协议。它提供了可靠、面向连接的数据传输服务,广泛应用于各种网络应用中。对于音视频传输,虽然TCP协议并不是最常用的传输协议&…

LVS实验——部署DR模式集群

目录 一、实验环境 二、配置 1、LVS 2、router 3、client 4、RS 三、配置策略 四、测试 1.Director服务器采用双IP桥接网络,一个是VPP,一个DIP 2.Web服务器采用和DIP相同的网段和Director连接 3.每个Web服务器配置VIP 4.每个web服务器可以出外网…

《Advanced RAG》-11-RAG查询分类和细化

总结 文章介绍了两种高级的检索增强生成(RAG)技术:自适应 RAG 和 RQ-RAG,以及它们在问题复杂性学习和查询细化方面的应用和优势,以及如何通过小型模型的训练来提高这些技术的性能。 摘要 传统 RAG 技术虽然能够减少大型…

「MyBatis」数据库相关操作2

🎇个人主页 🎇所属专栏:Spring 🎇欢迎点赞收藏加关注哦! #{} 和 ${} 我们前面都是采用 #{} 对参数进行赋值,实际上也可以用 ${} 客户端发送⼀条 SQL 给服务器后,大致流程如下: 1.…

51单片机之动态数码管显示

一、硬件介绍 LED数码管是一种由多个发光二极管(LED)封装在一起,形成“8”字型的显示器件。它广泛用于仪表、时钟、车站、家电等场合,用于显示数字、字母或符号。 通过控制点亮a b c d e f g dp来显示数字,本实验开发板…

前端八股文笔记【三】

JavaScript 基础题型 1.JS的基本数据类型有哪些 基本数据类型:String,Number,Boolean,Nndefined,NULL,Symbol,Bigint 引用数据类型:object NaN是一个数值类型,但不是…