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

设计模式使用场景实现示例及优缺点(行为型模式——策略模式)

在遥远的王国里,有三个重要的角色:国王策略模式、他的皇家顾问算法家族,以及年轻的骑士接口。国王策略模式统治着整个王国,他的职责是确保每一个编程问题都能找到最合适的解决方案。

有一天,王国遇到了一场危机。编程王国中的一条巨龙,名叫“复杂性”,不断地改变自己的形态和行为,让程序员们疲于应对。面对这种情况,国王策略模式召集了他的皇家顾问算法家族。

算法家族中的成员包括快排骑士、归并骑士和冒泡骑士,他们每一个都有独特的技能和解决问题的方法。国王策略模式知道,这些骑士们的力量需要得到充分发挥,但他们的行动必须有组织、有协调。

于是,国王策略模式召见了年轻的骑士接口。接口骑士是一个精通沟通与协调的角色,他能让不同的算法骑士在合适的时候出场,发挥各自的优势。

策略模式国王说:“年轻的接口骑士,你需要创建一个共同的接口,让所有的算法骑士都能遵循这个接口来行动。这样一来,我们就能在遇到不同情况时,根据需要选择最适合的骑士出战。”

接口骑士接受了任务,开始设计一个通用的接口。这个接口规定了所有算法骑士必须遵循的方法和行为。无论是快排骑士、归并骑士还是冒泡骑士,他们都必须实现这个接口,确保可以被无缝调用和替换。

很快,接口设计完成了,算法家族的每个成员都被重新训练,适应新的接口。这样一来,当巨龙复杂性再次来袭时,接口骑士可以迅速选择合适的算法骑士来对抗它。

例如,当龙表现出需要快速排序的特性时,接口骑士会召唤快排骑士;当巨龙需要稳定排序时,接口骑士会召唤归并骑士;而当情况简单时,冒泡骑士便会上场。

通过创建一个共同的接口,将不同的算法封装成独立的类,并使它们之间可以相互替换。

策略模式(Strategy Pattern)

策略模式(Strategy Pattern)是一种行为设计模式,它能够在运行时选择最适合的算法或行为,同时能够将算法族封装成独立的类,并使它们之间可以相互替换。这种模式是通过创建一个共同的接口,而后将不同的行为或算法封装在不同的策略类中实现的。每个策略类都遵循相同的接口,从而保持策略的独立性与互换性。

核心组件

  • Strategy(策略接口):这是一个共同的接口,它定义了所有支持的算法的抽象方法。任何具体策略都必须实现这个接口。
  • ConcreteStrategy(具体策略):实现策略接口的类,提供具体的算法实现。
  • Context(上下文):用来维护对策略对象的引用,它可以定义一个接口,让策略对象根据上下文来选择适当的算法。

适用场景

  1. 多种算法或行为
    • 当一个类存在多种行为,且使用条件时,可以将这些行为封装成不同的策略。
  2. 避免使用多重条件选择语句
    • 使用策略模式可以避免使用多重条件选择语句,这样可以更容易维护和扩展。
  3. 需要动态地改变算法或行为
    • 当算法或行为需要经常改变时,使用策略模式可以提供更好的代码组织和重新使用。
  4. 行为变化独立于使用行为的客户
    • 需要将行为与客户代码解耦,使得行为的改变不会影响客户代码。

实现实例

以电商系统的支付功能为例,假设需要支持多种支付方式(如信用卡、PayPal、比特币等)。使用策略模式可以定义一个支付接口(PaymentStrategy),并为每种支付方式实现一个具体的策略类。上下文(PaymentContext)可以持有一个支付策略引用,根据不同的用户选择使用不同的支付策略:

策略接口(Strategy Interface)

这个接口定义了所有支持的算法或行为的抽象方法。每个具体的策略类都必须实现这个接口。

public interface PaymentStrategy {void pay(int amount);  // 定义支付行为的方法,每种支付策略都需要实现这个方法
}
具体策略类(Concrete Strategy Classes)

这些类实现了策略接口,并提供了具体的算法实现。

public class CreditCardStrategy implements PaymentStrategy {public void pay(int amount) {System.out.println("Paid " + amount + " using Credit Card");  // 信用卡支付实现}
}public class PayPalStrategy implements PaymentStrategy {public void pay(int amount) {System.out.println("Paid " + amount + " using PayPal");  // PayPal支付实现}
}public class BitcoinStrategy implements PaymentStrategy {public void pay(int amount) {System.out.println("Paid " + amount + " using Bitcoin");  // 比特币支付实现}
}
上下文类(Context Class)

这个类用于维护对策略对象的引用。它可以定义一个方法让策略对象根据上下文来选择适当的算法。

public class PaymentContext {private PaymentStrategy strategy;  // 维护一个对策略对象的引用public PaymentContext(PaymentStrategy strategy) {this.strategy = strategy;  // 构造函数中设置策略对象}public void setStrategy(PaymentStrategy strategy) {this.strategy = strategy;  // 允许在运行时改变策略}public void executePayment(int amount) {strategy.pay(amount);  // 执行支付,具体行为取决于策略对象}
}
客户端代码(Client Code)

这部分代码演示了如何使用策略模式来改变对象的行为。

public class Client {public static void main(String[] args) {PaymentContext context = new PaymentContext(new CreditCardStrategy());context.executePayment(100);  // 使用信用卡策略支付100context.setStrategy(new PayPalStrategy());context.executePayment(200);  // 更改策略为PayPal并支付200context.setStrategy(new BitcoinStrategy());context.executePayment(300);  // 更改策略为比特币并支付300}
}

优缺点

优点
  1. 封装性好
    • 策略模式将每个变化的策略封装到独立的类中,使得每个策略可以独立于客户端实现变化。
  2. 易于扩展
    • 策略模式提供了一种扩展机制,新的策略类可以很容易地添加进现有系统中。
  3. 避免使用多重条件选择语句
    • 策略模式允许动态地改变行为,客户端仅需更改配置,无需修改代码。
缺点
  1. 客户端必须知道所有策略
    • 客户端需要了解所有的策略类,并自行决定使用哪一个策略类。
  2. 策略族的增多
    • 随着策略族的增加,各种策略类的数目也会增加,每个策略都需要对外暴露,这就增加了系统的复杂性。

类图

+----------------+         +------------------+
|     Context    |-------->|     Strategy     |
+----------------+         +------------------+
| - strategy:    |         | + execute()      |
|   Strategy     |         +------------------+
| + setStrategy()|                 ^
| + execute()    |                 |
+----------------+                 ||+-------------------+--------+--------+----------------+|                   |                 |                |
+---------------+ +-----------------+ +----------------+ +--------------+
|ConcreteStrategyA| |ConcreteStrategyB| |ConcreteStrategyC| | ...          |
+---------------+ +-----------------+ +----------------+ +--------------+
| + execute()   | | + execute()     | | + execute()    | | + execute()   |
+---------------+ +-----------------+ +----------------+ +--------------+

总结

策略模式提供了一种灵活的方式来切换对象的行为,增强了代码的可维护性和扩展性。它帮助将行为封装为对象,可以在运行时互换,这使得它在需要支持多种行为的系统中非常有用。这种模式特别适合于那些算法或行为多样化的场景,可以有效地帮助系统遵守开闭原则,即对扩展开放,对修改关闭。通过策略模式,程序员可以方便地添加新的策略而不影响现有的系统,并且能够在运行时动态地改变对象的行为。

相关文章:

设计模式使用场景实现示例及优缺点(行为型模式——策略模式)

在遥远的王国里,有三个重要的角色:国王策略模式、他的皇家顾问算法家族,以及年轻的骑士接口。国王策略模式统治着整个王国,他的职责是确保每一个编程问题都能找到最合适的解决方案。 有一天,王国遇到了一场危机。编程王…...

ReactRouter v6升级的步骤

React Router v6 引入了一个 Routes 组件&#xff0c;它有点像 Switch &#xff0c;但功能要强大得多。与 Switch 相比&#xff0c; Routes 的主要优势在于&#xff1a; <Routes> 中的所有 <Route> 和 <Link> 都是相对的。这导致在 <Route path> 和 &…...

【JVM实战篇】内存调优:内存问题诊断+案例实战

文章目录 诊断内存快照在内存溢出时生成内存快照MAT分析内存快照MAT内存泄漏检测的原理支配树介绍如何在不内存溢出情况下生成堆内存快照&#xff1f;MAT查看支配树MAT如何根据支配树发现内存泄漏 运行程序的内存快照导出和分析快照**大文件的处理** 案例实战案例1&#xff1a;…...

专业条码二维码扫描设备和手机二维码扫描软件的区别?

条码二维码技术已广泛应用于我们的日常生活中&#xff0c;从超市结账到公交出行&#xff0c;再到各类活动的入场验证&#xff0c;条码二维码的便捷性不言而喻&#xff0c;而在条码二维码的扫描识别读取过程中&#xff0c;专业扫描读取设备和手机二维码扫描软件成为了两大主要工…...

基于嵌入式Linux的高性能车载娱乐系统设计与实现 —— 融合Qt、FFmpeg和CAN总线技术

随着汽车智能化的发展&#xff0c;车载娱乐系统已成为现代汽车的标配。本文介绍了一个基于Linux的车载娱乐系统的设计与实现过程。该系统集成了音视频娱乐、导航、车辆信息显示等功能&#xff0c;旨在提供安全、便捷、丰富的驾驶体验。 1. 项目概述 随着汽车智能化的发展&…...

探索IP形象设计:快速掌握设计要点

随着市场竞争的加剧&#xff0c;越来越多的企业开始关注品牌形象的塑造和推广。在品牌形象中&#xff0c;知识产权形象设计是非常重要的方面。在智能和互联网的趋势下&#xff0c;未来的知识产权形象设计可能会更加关注数字和社交网络。通过数字技术和社交媒体平台&#xff0c;…...

泛微Ecology8明细表对主表赋值

文章目录 [toc]1.需求及效果1.1 需求1.2 效果2.思路与实现3.结语 1.需求及效果 1.1 需求 在明细表中的项目经理&#xff0c;可以将值赋值给主表中的项目经理来作为审批人员 1.2 效果 在申请人保存或者提交后将明细表中的人名赋值给主表中对应的值2.思路与实现 在通过js测…...

opencv—常用函数学习_“干货“_5

目录 十五、图像分割 简单阈值分割 (threshold) 自适应阈值分割 (adaptiveThreshold) 颜色范围分割 (inRange) 分水岭算法 (watershed) 泛洪填充 (floodFill) GrabCut算法 (grabCut) 距离变换 (distanceTransform) 最大稳定极值区域检测 (MSER) 均值漂移滤波 (pyrMean…...

JAVA零基础学习1(CMD、JDK、环境变量、变量和键盘键入、IDEA)

JAVA零基础学习1&#xff08;CMD、JDK、环境变量、变量和键盘键入、IDEA&#xff09; CMD常见命令配置环境变量JDK的下载和安装变量变量的声明和初始化声明变量初始化变量 变量的类型变量的作用域变量命名规则示例代码 键盘键入使用 Scanner 类读取输入步骤示例代码 常用方法处…...

Redis的安装配置及IDEA中使用

目录 一、安装redis&#xff0c;配置redis.conf 1.安装gcc 2.将redis的压缩包放到指定位置解压 [如下面放在 /opt 目录下] 3.编译安装 4.配置redis.conf文件 5.开机自启 二、解决虚拟机本地可以连接redis但是主机不能连接redis 1.虚拟机网络适配器网络连接设置为桥接模式…...

ubuntu 物理内存爆炸而不使用虚拟内存的问题

ubuntu 物理内存不足时有时候会不去使用虚拟内存&#xff0c;让虚拟内存空闲&#xff0c;而直接关闭占用内存的进程&#xff0c;如果在进行模型测试或训练时&#xff0c;就会导致训练或测试进程被杀死。 1. 修改 swappiness&#xff1a; cat /proc/sys/vm/swappiness sudo sysc…...

Python实现音频均衡和降噪

使用librosa库来读取音频文件&#xff0c;音频处理是一个复杂过程&#xff0c;这里只是简单的进行降噪和均衡。 import librosa import soundfile as sf def improve_audio_quality(input_file, output_file): # 读取音频文件 audio, sample_rate librosa.load(input_…...

【JavaScript 算法】贪心算法:局部最优解的构建

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、贪心算法的基本概念贪心算法的适用场景 二、经典问题及其 JavaScript 实现1. 零钱兑换问题2. 活动选择问题3. 分配问题 三、贪心算法的应用四、总结 贪心算法&#xff08;Greedy Algorithm&#xff09;是一种逐步构建解…...

Azcopy Sync同步Azure文件共享

文章目录 Azcopy Sync同步文件共享一、工作原理二、安装 AzCopy在 Windows 上在 Linux 上 三、资源准备1. 创建源和目标 Azure 存储账户2. 创建源和目标文件共享3. 确定路径4. 生成源和目的存储账户的共享访问签名&#xff08;SAS&#xff09;令牌配置权限示例生成的 URL 四、A…...

单例模式 饿汉式和懒汉式的区别

单例模式&#xff08;Singleton Pattern&#xff09;是设计模式中最简单、最常见、最容易实现的一种模式。它确保一个类仅有一个实例&#xff0c;并提供一个全局访问点。单例模式主要有两种实现方式&#xff1a;饿汉式&#xff08;Eager Initialization&#xff09;和懒汉式&am…...

Python中的模块和包的定义以及如何在Python中导入和使用它们

在Python中&#xff0c;模块&#xff08;Module&#xff09;和包&#xff08;Package&#xff09;是组织代码以便重用和共享的基本单元。它们使得Python代码更加模块化&#xff0c;易于管理和维护。 模块&#xff08;Module&#xff09; 模块是一个包含Python代码的文件&…...

设计模式使用场景实现示例及优缺点(结构型模式——组合模式)

结构型模式 组合模式&#xff08;Composite Pattern&#xff09; 组合模式使得用户对单个对象和组合对象的使用具有一致性。 有时候又叫做部分-整体模式&#xff0c;它使我们树型结构的问题中&#xff0c;模糊了简单元素和复杂元素的概念&#xff0c;客户程序可以像处理简单元…...

《系统架构设计师教程(第2版)》第11章-未来信息综合技术-06-云计算(Cloud Computing) 技术概述

文章目录 1. 相关概念2. 云计算的服务方式2.1 软件即服务 (SaaS)2.2 平台即服务 (PaaS)2.3 基础设施即服务 (IaaS)2.4 三种服务方式的分析2.4.1 在灵活性2.4.2 方便性方 3. 云计算的部署模式3.1 公有云3.2 社区云3.3 私有云3.4 混合云 4. 云计算的发展历程4.1 虚拟化技术4.2 分…...

网络安全工作者如何解决网络拥堵

网络如同现代社会的血管&#xff0c;承载着信息的血液流动。然而&#xff0c;随着数据流量的激增&#xff0c;网络拥堵已成为不容忽视的问题&#xff0c;它像是一场数字世界的交通堵塞&#xff0c;减缓了信息传递的速度&#xff0c;扰乱了网络空间的秩序。作为网络安全的守护者…...

电脑显示mfc140u.dll丢失的修复方法,总结7种有效的方法

mfc140u.dll是什么&#xff1f;为什么电脑会出现mfc140u.dll丢失&#xff1f;那么mfc140u.dll丢失会给电脑带来什么影响&#xff1f;mfc140u.dll丢失怎么办&#xff1f;今天详细给大家一一探讨一下mfc140u.dll文件与mfc140u.dll丢失的多种不同解决方法分享&#xff01; 一、mfc…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

C++ 基础特性深度解析

目录 引言 一、命名空间&#xff08;namespace&#xff09; C 中的命名空间​ 与 C 语言的对比​ 二、缺省参数​ C 中的缺省参数​ 与 C 语言的对比​ 三、引用&#xff08;reference&#xff09;​ C 中的引用​ 与 C 语言的对比​ 四、inline&#xff08;内联函数…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代&#xff0c;海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构&#xff0c;在处理大规模数据抓取任务时展现出强大的能力。然而&#xff0c;随着业务规模的不断扩大和数据抓取需求的日益复杂&#xff0c;传统…...