当前位置: 首页 > 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…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

Linux系统部署KES

1、安装准备 1.版本说明V008R006C009B0014 V008&#xff1a;是version产品的大版本。 R006&#xff1a;是release产品特性版本。 C009&#xff1a;是通用版 B0014&#xff1a;是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存&#xff1a;1GB 以上 硬盘&#xf…...

【Linux】Linux安装并配置RabbitMQ

目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的&#xff0c;需要先安…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...

[特殊字符] 手撸 Redis 互斥锁那些坑

&#x1f4d6; 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作&#xff0c;想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁&#xff0c;也顺便跟 Redisson 的 RLock 机制对比了下&#xff0c;记录一波&#xff0c;别踩我踩过…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”

非常好&#xff0c;我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题&#xff0c;统一使用 二重复合函数&#xff1a; z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y))​ 来全面说明。我们会展示其全微分形式&#xff08;偏导…...