9.策略模式:思考与解读
原文地址:策略模式:思考与解读 更多内容请关注:7.深入思考与解读设计模式
引言
你是否曾遇到过这样的情况:在一个系统中,有许多算法或策略,每种策略的实现逻辑相似,但在某些情况下需要进行替换和扩展?当你面对这些问题时,是否想过,能否在不修改代码的情况下轻松地切换不同的策略或算法?
如果这些问题引起了你的思考,那你可能需要了解一种叫做“策略模式”的设计模式。策略模式究竟是什么?它如何能帮助我们解决上述问题?它适用于哪些场景?我们将通过一系列问题来引导你一步步探讨这一模式。
什么是策略模式?
首先,让我们从一个简单的问题开始。
问题1:当你有多个算法或者策略时,通常如何选择其中一个?
假设你正在编写一个程序,涉及到不同的支付方式,比如支付宝、微信支付和银行卡支付。每种支付方式都需要不同的算法来完成支付。那么,如何选择并应用其中的一种支付方式呢?
问题2:你是否曾经将不同的算法直接写在一个类中,导致类的逻辑过于复杂?
想象一下,如果你将所有支付方式的逻辑都放在一个类里,会发生什么?这个类会变得非常庞大和难以维护。如果你需要增加新的支付方式,你还需要修改这个类,是不是很不方便?
问题3:如果有一种方法可以将不同的支付方式(算法)封装在独立的类中,并且能够动态地在运行时进行切换,你会觉得这种方法如何?
是否想过,将支付方式封装在不同的类中,并且在程序运行时根据用户的选择动态切换支付方式,是否可以避免上述问题?
答案就是策略模式。策略模式允许你将不同的算法或策略封装成独立的类,这样客户端代码只需要选择和应用合适的策略,而不需要关心算法的具体实现。
策略模式的核心构成
策略模式通常由以下几个关键部分组成。那么,如何才能理解它们呢?我们来逐一思考。
问题4:在策略模式中,谁来决定使用哪种策略?
在一个系统中,是否需要有一个“控制者”来管理和切换不同的策略?这个控制者的角色是什么?它应该如何与策略进行交互?
在策略模式中,上下文类(Context) 扮演了这个“控制者”的角色。它持有一个策略接口的引用,并负责在运行时根据需要切换具体的策略。
问题5:如果不同的策略类实现了相同的接口,能否让这些策略类的使用变得更加一致和灵活?
策略接口(Strategy) 是策略模式的关键部分。它定义了所有具体策略类需要实现的方法。这样,所有的具体策略类(如支付方式)都可以通过这个统一的接口进行访问。你能否想象到,当策略类实现了相同的接口时,它们可以被统一地调用,而无需关心它们的具体实现?
问题6:如何实现不同策略类的具体逻辑?
每个具体的策略类将如何实现策略接口,并在特定的场景下提供不同的算法?如果我们将算法封装在独立的类中,是否能够提高代码的可维护性?你能举一个例子,说明一个具体的策略类如何实现不同的算法吗?
示例:
我们来思考一个支付系统的例子。你是否觉得,我们可以将每种支付方式(例如支付宝、微信支付、银行卡支付)作为具体的策略类,它们都实现一个统一的支付接口?
问题7:那么,客户端如何与策略模式进行交互?
假设我们已经创建了多个策略类(不同的支付方式),但客户端如何选择并使用这些策略类呢?客户端需要做什么才能改变策略呢?
问题8:如果用户希望在运行时切换策略,如何做到这一点?
策略模式的一个关键特点是能够在运行时动态选择不同的策略。你认为,如何实现策略的动态切换?我们是否需要提供一个方法来让客户端更新或更改当前的策略?这样,用户就能根据实际情况选择合适的支付方式。
策略模式的优点和缺点
策略模式具有很多的优点,但它是否适用于所有场景呢?
问题9:策略模式带来的最大好处是什么?它能解决哪些问题?
通过将不同的算法封装成独立的策略类,策略模式能帮助我们避免复杂的条件语句。这是否意味着我们的代码更加清晰和易于维护?
问题10:使用策略模式时,可能会面临哪些挑战?
每种策略都需要一个独立的类,这是否会导致类的数量增加?这样做是否会增加代码的复杂度?策略模式是否适用于所有情况,还是在某些情况下可能导致不必要的复杂性?
策略模式的实际应用
那么,策略模式在现实生活中有哪些实际应用呢?我们来思考一些问题:
问题11:你能想到哪些场景,策略模式能够发挥作用?
比如支付系统,还是其他场景,如排序算法、日志输出策略、数据库查询策略等。你能举出一些实际的例子来说明,策略模式如何在这些场景中提高灵活性和可扩展性?
问题12:如何将策略模式与其他设计模式结合使用?
策略模式与其他设计模式(如工厂模式、观察者模式等)是否能够结合使用?你能想到它们之间的协同作用吗?
接下来,我们将通过具体的代码示例来加深理解策略模式。
策略模式深入解读
一、引言
策略模式(Strategy Pattern)是一种非常有用的设计模式,它让我们可以通过选择不同的策略(或算法)来改变某个类的行为,而不需要修改类的代码。为了更好地理解这一概念,我们将一步步地深入解读策略模式的含义和实际应用。
二、简单理解:什么是策略模式?
1. 什么是策略模式?
策略模式是一个行为型设计模式,它让我们能够在运行时选择并切换不同的“策略”来解决问题。策略指的是算法或行为。当我们有多个算法可以选择时,策略模式帮助我们将这些算法封装起来,并且在不改变客户端代码的前提下,切换不同的算法。
简单来说,策略模式就是一种允许你在不同的情况下选择和切换“方法”的方式。
举个简单的例子:想象一下,你在一个商店购买商品,支付方式有多种选择:支付宝、微信支付、银行卡支付等。每种支付方式都可以看作是一种策略,你可以根据实际情况选择一种支付方式。
2. 策略模式的主要组成
策略模式的设计涉及三个主要部分:
-
上下文(Context):它是使用策略的环境。它持有一个策略对象,并在需要时调用它。
-
策略接口(Strategy):这是一个定义了算法的接口,所有具体策略都需要实现这个接口。
-
具体策略(Concrete Strategy):这些是实现策略接口的具体算法类。
三、用自己的话解释:如何理解策略模式?
1. 类比实际生活中的场景
想象你是一位司机,要选择不同的交通工具去不同的地方:
-
如果去的地方近,你可能选择走路;
-
如果地方远,你可能选择开车;
-
如果天气不好,你可能选择打车。
在这个场景中,“走路”、“开车”、“打车”就是三种策略,而你根据具体情况(距离、天气等)选择其中一种策略。每次选择的策略会影响你的出行方式,而你不需要改变你作为司机的角色。
2. 为什么要使用策略模式?
如果你直接在代码里使用大量的 if-else
或 switch
来判断该使用哪种算法或方法,那样的代码会变得复杂且难以维护。当你需要新增一种算法时,你需要修改已有的代码,这违背了“开闭原则”(对扩展开放,对修改封闭)。策略模式则通过将不同的算法封装成独立的策略类,避免了修改现有代码,只需要增加新的策略类即可。
四、深入理解:策略模式的实现
接下来,我们将通过具体的代码示例来加深理解。
示例:计算不同商品的折扣
假设我们有一个电商系统,需要根据不同的促销策略计算商品的价格。例如:
-
满200元打9折
-
满100元打8折
-
满50元减20元
我们可以用策略模式来实现不同的折扣策略。
1. 策略接口:定义算法
# 策略接口:定义折扣计算的接口 class DiscountStrategy:def apply_discount(self, price):pass
2. 具体策略:实现不同的折扣计算方式
# 满200元打9折
class DiscountFor200Strategy(DiscountStrategy):def apply_discount(self, price):if price >= 200:return price * 0.9return price# 满100元打8折
class DiscountFor100Strategy(DiscountStrategy):def apply_discount(self, price):if price >= 100:return price * 0.8return price# 满50元减20元
class DiscountFor50Strategy(DiscountStrategy):def apply_discount(self, price):if price >= 50:return price - 20return price
3. 上下文类:购物车(选择策略)
# 上下文:购物车类,使用策略计算折扣后价格 class ShoppingCart:def __init__(self, strategy: DiscountStrategy):self.strategy = strategydef set_strategy(self, strategy: DiscountStrategy):self.strategy = strategydef calculate_price(self, price):return self.strategy.apply_discount(price)
4. 使用策略
# 创建购物车实例,设置不同的折扣策略 cart = ShoppingCart(DiscountFor200Strategy()) print(cart.calculate_price(250)) # 输出:225.0(200元以上打9折)cart.set_strategy(DiscountFor100Strategy()) print(cart.calculate_price(150)) # 输出:120.0(100元以上打8折)cart.set_strategy(DiscountFor50Strategy()) print(cart.calculate_price(80)) # 输出:60.0(50元以上减20元)
代码解析:
-
DiscountStrategy:这是一个策略接口,所有具体的策略类都需要实现
apply_discount
方法。 -
具体策略类:
DiscountFor200Strategy
、DiscountFor100Strategy
和DiscountFor50Strategy
是三种不同的折扣策略,它们实现了apply_discount
方法,分别根据价格进行不同的折扣计算。 -
ShoppingCart
类:这是上下文类,它接受一个策略对象,并使用该策略来计算商品价格。通过set_strategy
方法,可以随时更换策略。
五、解释给别人:如何讲解策略模式?
1. 用简单的语言解释
策略模式让你能够根据不同的需求选择不同的“方法”。比如,你要计算商品价格的折扣,根据不同的条件(如价格大小),你可以选择不同的折扣策略。这些折扣策略像是各种“方法”,而你通过策略模式,能够在不修改代码的前提下,灵活地更换策略。
2. 为什么要使用策略模式?
使用策略模式可以避免代码中出现大量的 if-else
或 switch
语句。当你需要添加一种新的策略时,只需要创建一个新的策略类,且不需要修改已有代码。这不仅使代码更简洁,还能提高可扩展性和维护性。
六、总结
通过一系列问题的探讨,我们逐步揭示了策略模式的核心概念和实现方式。策略模式不仅能帮助我们解决不同算法的选择问题,还能提高系统的灵活性和可维护性。然而,它也有一定的缺点,比如类数量的增加和复杂性的提升。
我们可以得出以下结论:
-
策略模式 是一种允许我们在运行时灵活选择不同算法的设计模式;
-
它通过定义策略接口、具体策略和上下文类,将算法封装起来,避免修改现有代码;
-
策略模式的主要优势是 扩展性 和 灵活性,它避免了使用大量的条件判断语句,让代码更易于维护。
策略模式的优点:
-
开闭原则:可以在不修改现有代码的情况下扩展新的策略。
-
灵活性:运行时可以根据需要选择合适的策略。
-
简化代码:避免了大量的条件判断,使得代码更加清晰。
策略模式的缺点:
-
类的数量增加:每种策略都需要创建一个策略类,可能会导致类数量增多。
相关文章:
9.策略模式:思考与解读
原文地址:策略模式:思考与解读 更多内容请关注:7.深入思考与解读设计模式 引言 你是否曾遇到过这样的情况:在一个系统中,有许多算法或策略,每种策略的实现逻辑相似,但在某些情况下需要进行替换和扩展&am…...

【HCIA】简易的两个VLAN分别使用DHCP分配IP
前言 之前我们通过 静态ip地址实现了Vlan间通信 ,现在我们添加一个常用的DHCP功能。 文章目录 前言1. 配置交换机2. 接口模式3. 全局模式后记修改记录 1. 配置交换机 首先,使用DHCP,需要先启动DHCP服务: [Huawei]dhcp enable I…...
【设计模式-4】深入理解设计模式:工厂模式详解
在软件开发中,对象的创建是一个基础但至关重要的环节。随着系统复杂度的增加,直接使用new关键字实例化对象会带来诸多问题,如代码耦合度高、难以扩展和维护等。工厂模式(Factory Pattern)作为一种创建型设计模式&#…...
Spring Boot 整合 JavaFX 核心知识点详解
1. 架构设计与集成模式 1.1 Spring Boot 与 JavaFX 的分层架构设计 Spring Boot 与 JavaFX 的整合需要精心设计的分层架构,以充分利用两个框架的优势。 标准分层架构 ┌────────────────────────────────────────────────…...
Spring MVC DispatcherServlet 的作用是什么? 它在整个请求处理流程中扮演了什么角色?为什么它是核心?
DispatcherServlet 是 Spring MVC 框架的绝对核心和灵魂。它扮演着前端控制器(Front Controller)的角色,是所有进入 Spring MVC 应用程序的 HTTP 请求的统一入口点和中央调度枢纽。 一、 DispatcherServlet 的核心作用和职责: 请…...
亚马逊英国站FBA费用重构:轻小商品迎红利期,跨境卖家如何抢占先机?
一、政策背景:成本优化成平台与卖家共同诉求 2024年4月,亚马逊英国站(Amazon.co.uk)发布近三年来力度最大的FBA费用调整方案,标志着英国电商市场正式进入精细化成本管理时代。这一决策背后,是多重因素的叠…...
Redis在.NET平台中的各种应用场景
关键点总结 连接管理:所有示例都使用ConnectionMultiplexer来管理Redis连接,它是线程安全的,应该在整个应用程序中重用。 键设计:良好的键命名规范很重要,通常使用冒号分隔的层次结构(如page:home:pv)。 数据序列化&…...
近几年字节测开部分面试题整理
文章目录 前言一、面试问题1. 在浏览器url上写一个地址,请描述一下网络方面有哪些变化2. 堆栈数据存储位置3. HTTP POST请求支持的数据格式4. 缩容要注意些什么?5. Python中元组、数组、list和数组的区别6. Python中is和的区别7. HTTP与HTTPS8. 已知两个…...

艾蒙顿桌面app下载-Emotn UI下载安装-emotn ui官方tv版安卓固件
在智能电视桌面应用的领域里,Emotn UI 凭借其简洁无广告、可自定义等特点,赢得了不少用户的关注。然而,小编深入了解后发现了一款更好用的电视桌面——乐看家桌面在诸多方面更具优势,能为你带来更优质的大屏体验。 乐看家桌面内置…...

3、ArkTS语言介绍
目录 基础知识函数函数声明可选参数Rest参数返回类型箭头函数(又名Lambda函数)闭包 类字段字段初始化getter和setter继承父类访问方法重写方法重载签名可见性修饰符(Public、Private、protected) 基础知识 ArkTS是一种为构建高性…...

修改了Element UI中组件的样式,打包后样式丢失
修改了Element UI中组件的样式,在本地运行没有问题,但是打包到线上发现样式丢失(样式全部不生效、或者有一部分生效,一部分不生效),问题在于css的加载顺序导致代码编译后样式被覆盖了, 解决办法…...
Linux GPIO驱动开发实战:Poll与异步通知双机制详解
1. 引言 在嵌入式Linux开发中,GPIO按键驱动是最基础也最典型的案例之一。本文将基于一个支持poll和异步通知双机制的GPIO驱动框架,深入剖析以下核心内容: GPIO中断与防抖处理环形缓冲区设计Poll机制实现异步通知(SIGIO)实现应用层交互方式 …...

【springsecurity oauth2授权中心】jwt令牌更换成自省令牌 OpaqueToken P4
前言 前面实现了授权中心授权,客户端拿到access_token后就能请求资源服务器接口 权限的校验都是在资源服务器上进行的,授权服务器颁发的access_token有限期是2小时,也就是说在2小时之内,不管授权服务器那边用户的权限如何变更都…...

诱骗协议芯片支持PD2.0/3.0/3.1/PPS协议,支持使用一个Type-C与电脑传输数据和快充取电功能
快充是由充电器端的充电协议和设备端的取电协议进行握手通讯进行协议识别来完成的,当充电器端的充电协议和设备端的取电协议握手成功后,设备会向充电器发送电压请求,充电器会根据设备的需求发送合适的电压给设备快速供电。 设备如何选择快充…...

变量在template里不好使,在setup好使?
问题: 自定义的一个函数 ,import导入后 setup里面使用正常 ,在template里面说未定义 作用域问题 在 Vue 的模板语法中,模板(template )里能直接访问的是组件实例上暴露的属性和方法。从代码看,…...

OpenCV 图形API(53)颜色空间转换-----将 RGB 图像转换为灰度图像函数RGB2Gray()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 将图像从 RGB 色彩空间转换为灰度。 R、G 和 B 通道值的常规范围是 0 到 255。生成的灰度值计算方式如下: dst ( I ) 0.299 ∗ src…...

Trae+DeepSeek学习Python开发MVC框架程序笔记(四):使用sqlite存储查询并验证用户名和密码
继续通过Trae向DeepSeek发问并修改程序,实现程序运行时生成数据库,用户在系统登录页面输入用户名和密码后,控制器通过模型查询用户数据库表来验证用户名和密码,验证通过后显示登录成功页面,验证失败则显示登录失败页面…...

超详细mac上用nvm安装node环境,配置npm
一、安装NVM 打开终端,运行以下命令来安装NVM: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash 然后就会出现如下代码: > Profile not found. Tried ~/.bashrc, ~/.bash_profile, ~/.zprofile, ~/.…...
STM32 串口通信
引言 在嵌入式系统开发中,串口通信是最基础且重要的通信方式之一。无论是设备调试、模块对接还是远程通信,串口都扮演着关键角色。本文将从通信协议原理出发,结合STM32F4系列MCU,深入讲解串口通信的硬件实现和软件配置࿰…...

hi3516cv610构建音频sample工程代码步骤
hi3516cv610构建音频sample工程代码步骤 sdk版本:Hi3516CV610_SDK_V1.0.1.0 硬件:非es8388 工程代码: 通过网盘分享的文件:audio_easy.zip 链接: https://pan.baidu.com/s/1gx61S_F3-pf6hPyfbGaRXg 提取码: 4gbg --来自百度网盘…...

12.QT-Combo Box|Spin Box|模拟点餐|从文件中加载选项|调整点餐份数(C++)
Combo Box QComboBox 表⽰下拉框 核⼼属性 属性说明currentText当前选中的⽂本currentIndex当前选中的条⽬下标.从0开始计算.如果当前没有条⽬被选中,值为-1editable是否允许修改设为true时, QComboBox 的⾏为就⾮常接近 QLineEdit ,也可以 设置 validatoriconSize下拉框图标…...

UML 顺序图:电子图书馆管理系统的交互之道
目录 一、初识 UML 顺序图 二、电子图书馆管理系统顺序图解析 (一)借阅流程 (二)归还流程 三、顺序图绘画 四、顺序图的优势与价值 五、总结 UML 顺序图是描绘系统组件交互的有力工具。顺序图直观展示消息传递顺序与对象协…...
分布式架构设计与应用:从理论到实践
在云计算、大数据与高并发场景的驱动下,分布式架构已成为现代软件系统的核心技术。它通过将计算、存储与业务逻辑分散到多台机器上,解决了单体架构的扩展性瓶颈与单点故障问题。本文将从设计原则、核心组件到典型应用场景,深入剖析分布式架构…...
Uniapp:view容器(容器布局)
目录 一、基本概述二、属性说明三、常用布局3.1 横向布局3.2 纵向布局3.3 更多布局3.3.1 纵向布局-自动宽度3.3.2 纵向布局-固定宽度3.3.3 横向布局-自动宽度3.3.4 横向布局-居中3.3.5 横向布局-居右3.3.6 横向布局-平均分布3.3.7 横向布局-两端对齐3.3.8 横向布局-自动填充3.3…...

访问者模式:分离数据结构与操作的设计模式
访问者模式:分离数据结构与操作的设计模式 一、模式核心:将操作从数据结构中分离,支持动态添加新操作 在软件开发中,当数据结构(如树、集合)中的元素类型固定,但需要频繁添加新的操作…...

【AI训练环境搭建】在IDE(Pycharm或VSCode)上使用WSL2+Ubuntu22.04+Conda+Tensorflow+GPU进行机器学习训练
本次实践将在IDE(Pycharm或VSCode)上使用WSL2Ubuntu22.04TensorflowGPU进行机器学习训练。基本原理是在IDE中拉起WSL2中的Python解释器,并运行Python程序。要运行CondaTensorflowGPU你可能需要进行以下准备工作。 1. 此示例中将使用一个mnis…...

Leetcode19(亚马逊真题):删除链表的倒是第N个节点
题目分析 删除节点关键:找到被删节点的前一个节点,指针指向 虚拟头节点,方便删除头结点,形成统一操作 为啥要让快指针先行? 我认为更好懂的一种解释:快指针先行n步,这样快慢指针之间形成了一…...

Hadoop+Spark 笔记 2025/4/21
读书笔记 定义 1. 大数据(Big Data) - 指传统数据处理工具难以处理的海量、高速、多样的数据集合,通常具备3V特性(Volume体量大、Velocity速度快、Variety多样性)。扩展后还包括Veracity(真实性&#x…...
千问2.5-VL-7B的推理、微调、部署_笔记2
接上篇:部署千问2.5-VL-7B_笔记1-CSDN博客 这里主要记录微调过程 一、模型微调 这里也使用ms-swift对qwen2.5和qwen2-vl进行自我认知微调和图像OCR微调,并对微调后的模型进行推理。ms-swift是魔搭社区官方提供的LLM工具箱,支持300大语言模…...

Redis从入门到实战基础篇
前言:Redis的安装包含在Redis从入门到实战先导篇中,需要的可移步至此节 目录 1.Redis简单介绍 2.初始Redis 2.1.认识NoSQL 2.2.认识Redis 2.3.安装Redis 3.Redis常见命令 3.1 Redis数据结构 3.2 通用命令 3.3 String命令 3.4 Key的层级结构 3…...