策略模式:优雅地实现可扩展的设计
策略模式:优雅地实现可扩展的设计
摘要: 策略模式是一种常用的设计模式,它可以帮助我们实现可扩展的、灵活的代码结构
。本文将通过一个计算器案例来介绍策略模式的概念、使用场景以及如何在实际项目中应用策略模式来提高代码的可维护性和可扩展性。
引言
在软件开发中,我们经常会遇到需要根据不同的条件选择不同的算法或行为
的情况。传统的做法是使用大量的if-else语句或switch语句
来实现这种选择逻辑,但这样的代码结构往往难以维护和扩展。策略模式提供了一种优雅的解决方案,它将不同的算法或行为封装成独立的策略类
,并通过一个上下文类
来选择并执行相应的策略。
策略模式的概念
策略模式是一种行为型设计模式,它定义了一系列的算法或行为,并将其封装成独立的策略类。这些策略类可以互相替换,使得算法或行为的选择可以在运行时动态地改变。策略模式的核心思想是将算法或行为的选择与具体的实现分离
,从而使得代码更加灵活、可维护和可扩展。
计算器案例
假设我们正在开发一个简单的计算器应用程序,该应用程序可以执行加法、减法、乘法和除法
操作。传统的做法是使用if-else语句或switch语句来根据用户输入的操作符执行相应的操作。然而,这样的实现方式存在以下问题:
- 如果需要添加新的操作,就需要修改已有的代码,
违反了开闭原则
。 - 如果需要修改某个操作的实现,就需要
修改多处代码
,增加了维护的难度。
下面我们将使用策略模式来重构这个计算器应用程序,使其更加灵活、可维护和可扩展。
策略模式的实现步骤
使用策略模式实现可扩展的代码结构可以分为以下几个步骤:
1. 定义策略接口
首先,我们需要定义一个策略接口,该接口声明了执行计算操作的方法。在我们的计算器案例中,我们可以将该接口命名为CalculatorStrategy
,并声明一个calculate
方法,用于执行具体的计算操作。
public interface CalculatorStrategy {double calculate(double num1, double num2);
}
2. 实现具体策略类
接下来,我们需要根据业务需求,实现具体的策略类。在我们的计算器案例中,我们可以实现加法、减法、乘法和除法四种策略类,分别对应不同的计算操作。
public class AdditionStrategy implements CalculatorStrategy {@Overridepublic double calculate(double num1, double num2) {return num1 + num2;}
}public class SubtractionStrategy implements CalculatorStrategy {@Overridepublic double calculate(double num1, double num2) {return num1 - num2;}
}public class MultiplicationStrategy implements CalculatorStrategy {@Overridepublic double calculate(double num1, double num2) {return num1 * num2;}
}public class DivisionStrategy implements CalculatorStrategy {@Overridepublic double calculate(double num1, double num2) {if (num2 != 0) {return num1 / num2;} else {throw new IllegalArgumentException("Divisor cannot be zero");}}
}
3. 定义上下文类
然后,我们需要定义一个上下文类,该类持有一个策略接口的引用,并提供一个方法来设置和执行策略。在我们的计算器案例中,我们可以将该上下文类命名为CalculatorContext
。
public class CalculatorContext {private CalculatorStrategy strategy;public void setStrategy(CalculatorStrategy strategy) {this.strategy = strategy;}public double executeStrategy(double num1, double num2) {return strategy.calculate(num1, num2);}
}
4. 使用策略模式
最后,在客户端代码中,我们可以通过实例化上下文类并设置相应的策略,来实现不同的计算操作。
public class CalculatorApp {public static void main(String[] args) {CalculatorContext context = new CalculatorContext();// 使用加法策略context.setStrategy(new AdditionStrategy());double result = context.executeStrategy(10, 5);System.out.println("Addition: " + result);// 使用减法策略context.setStrategy(new SubtractionStrategy());result = context.executeStrategy(10, 5);System.out.println("Subtraction: " + result);// 使用乘法策略context.setStrategy(new MultiplicationStrategy());result = context.executeStrategy(10, 5);System.out.println("Multiplication: " + result);// 使用除法策略context.setStrategy(new DivisionStrategy());result = context.executeStrategy(10, 5);System.out.println("Division: " + result);}
}
策略模式在工作中的一个简单应用
策略模式的优点
策略模式具有以下优点:
- 策略模式
将算法或行为的选择与具体的实现分离,使得代码更加灵活、可维护和可扩展
。 - 策略模式
符合开闭原则
,可以在不修改原有代码的情况下增加新的策略。 - 策略模式可以
提高代码的复用性
,不同的策略可以被多个上下文类共享使用。
策略模式的注意事项
在使用策略模式时需要注意以下事项:
- 策略模式适用于算法或行为之间相对独立的情况,
如果算法或行为之间存在复杂的依赖关系,可能不适合使用策略模式
。 - 策略模式的上下文类需要持有一个策略接口的引用,因此需要在上下文类中进行策略的选择和设置。
结论
策略模式是一种优雅地实现可扩展的设计的方法。通过将算法或行为封装成独立的策略类,并通过上下文类来选择和执行策略,可以使得代码更加灵活、可维护和可扩展。在实际项目中,合理地应用策略模式可以提高代码的可维护性和可扩展性,使得系统更加稳定和可靠。
案例参考链接:
- Refactoring Guru - Strategy Pattern
学习更多设计模式
相关文章:

策略模式:优雅地实现可扩展的设计
策略模式:优雅地实现可扩展的设计 摘要: 策略模式是一种常用的设计模式,它可以帮助我们实现可扩展的、灵活的代码结构。本文将通过一个计算器案例来介绍策略模式的概念、使用场景以及如何在实际项目中应用策略模式来提高代码的可维护性和可扩…...

从8个新 NFT AMM,聊聊能如何为 NFT 提供流动性
DeFi 的出现,开启了数字金融民主化的革命。其中,通过 AMM 自由创建流动性池极大地增加了 ERC-20 Token 的流动性,并为一些长尾 Token 解锁了价值的发现,因而今天在链上可以看到各种丰富的交易、借贷和杠杆等活动。 而另一方面&am…...

习题1.27
先写代码 (defn square [x] (* x x)) (defn expmod[base exp m](cond ( exp 0) 1(even? exp) (mod (square (expmod base (/ exp 2) m)) m):else (mod (* base (expmod base (- exp 1) m)) m)))(defn fermat-test[n](defn try-it [a](cond ( a n) (println "test end&qu…...

简单游戏截图_可控截取内容2
一个需求 我需要在场景中截取不同层级的截图(如只截模型或只截UI或只截外部相加看到的画面 或全都截或和Shader配合呈现人眼夜视仪热成像的画面切换) 将截图排到列表中,在场景UI中展示出来 如何做 相机要能够看到不同的画面 将当前帧画面存储下来 将存储的画面展示出…...

跨域+四种解决方法
文章目录 一、跨域二、JSONP实现跨域请求三、前端代理实现跨域请求四、后端设置请求头实现跨域请求五、Nginx代理实现跨域请求5.1 安装Nginx软件5.2 使用Ubuntu安装nginx 本文是在学习课程满神yyds后记录的笔记,强烈推荐读者去看此课程。 一、跨域 出于浏览器的同…...
RW-Everything的RwDrv.sys驱动调用
RW-Everything的RwDrv.sys驱动调用 一、RwDrv.sys二、示例代码三、总结 一、RwDrv.sys RW-Everything是一个硬件底层的工具,可用于物理内存、BIOS、PCI和IO端口的查看和修改,其基于驱动RwDrv.sys来实现,利用这个驱动可以实现系统的侵入。 二…...

0101docker mysql8镜像主从复制-运维-mysql
1 概述 主从复制是指将主数据库的DDL和DML操作通过二进制日志传到从库服务器,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步。 Mysql支持一台主库同时向多台从库进行复制,从库同时可以…...

uC-OS2 V2.93 STM32L476 移植:系统启动篇
前言 前两篇已经 通过 STM32CubeMX 搭建了 NUCLEO-L476RG 的 STM32L476RG 的 裸机工程,下载了 uC-OS2 V2.93 的源码,并把 uC-OS2 的源文件加入 Keil MDK5 工程 本篇适配 uC-OS2 的 系统定时器(Systick)与 PendSV_Handler…...

redis 集群 1:李代桃僵 —— Sentinel
目前我们讲的 Redis 还只是主从方案,最终一致性。读者们可思考过,如果主节点凌晨 3 点突发宕机怎么办?就坐等运维从床上爬起来,然后手工进行从主切换,再通知所有的程序把地址统统改一遍重新上线么?毫无疑问…...
重置 Macbook 中MySQL 的 root 用户密码
Mac上好久前安装测试用的MySQL的Root密码忘记,猜了些常用密码都不对,只能重置密码。 重置密码 1、关闭MySQL服务,可以直接在系统偏好里关闭 sudo /usr/local/mysql/support-files/mysql.server stop 2、进入安装目录,启动安全…...
2308C++搞笑的概念化
前一篇的概念化,太搞笑 元<类 T>概念 可画要求(T&t,整 i){t.画(i);}; 构 方形{空 画(整 i){打印(2*i);} };元<可画 T>空 f(T&t,整 i){t.画(i);t.画(i); }空 主(){方形 e;f(e,33); }用得着那么复杂吗?...
修改node_modules里的源码
最近在工作中使用到一款生成二维码的依赖(以vue项目为例讲解):vue-qr,安装的4.0.9版本的,在启动工程的时候报错: You may need an appropriate loader to handle this file type后我查阅各种资料发现 1&a…...
【每日一题Day287】LC24 两两交换链表中的节点 | 模拟 递归
两两交换链表中的节点【LC24】 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 周赛暂停一周啦 思路:模拟 记录前驱…...
Java ~ Collection/Executor ~ PriorityBlockingQueue【源码】
前言 相关系列 《Java ~ Collection【目录】》(持续更新)《Java ~ Executor【目录】》(持续更新)《Java ~ Collection/Executor ~ PriorityBlockingQueue【源码】》(学习过程/多有漏误/仅作参考/不再更新)…...
Java后台生成微信小程序码并以流的形式返回给前端
后端代码 获取access_token import net.sf.json.JSONObject;public class WeChatUtil {/*** 获取token*/private static String ACCESSTOKENURL "https://api.weixin.qq.com/cgi-bin/token?grant_typeclient_credential&appid{appId}&secret{appSecret}"…...

AtcoderABC226场
A - Round decimalsA - Round decimals 题目大意 给定一个实数X,它最多可以使用三位小数表示,而且X的小数点后有三位小数。将X四舍五入到最接近的整数并打印结果。 思路分析 可以使用round函数进行四舍五入 知识点 round(x) 是一个用来对数字进行四…...

Linux知识点 -- VS Code远程连接服务器协助开发
Linux知识点 – VS Code远程连接服务器协助开发 文章目录 Linux知识点 -- VS Code远程连接服务器协助开发一、VS Code的使用1.使用VS Code进行C语言编译与运行2.使用VS Code进行C代码的编译与运行 二、使用VS Code连接云服务器三、使用VS Code进行GDB调试 一、VS Code的使用 1…...

blender基础认识(选项开关、工具栏、视图等)
文章目录 引言一、大纲选项开关和保存启动文件1. 大纲选项1. 禁用选中2. 视图影藏3. 视图禁用4. 渲染禁用 2. 保存启动文件 二、工具栏和侧边栏1. 左侧工具栏2. 右侧工具栏 三、视图1. 视角2. 缩放3. 拖拽4. 摄像机视角5. 切换正交视图6. 局部视图7. 显示隐藏 四、添加删除物体…...
React Hooks 中的属性详解
React Hooks 是 React 16.8 版本中新增的特性,允许我们在不编写 class 的情况下使用 state 和其他的 React 特性。Hooks 是一种可以让你在函数组件中“钩入” React 特性的函数。以下是一些常用的 React Hooks,并附有详细的用法和代码示例。 1. useStat…...
工作遇到问题与解决办法(一)
一、构建父子工程 父 <groupId>com.ruoyi</groupId> <artifactId>ruoyi</artifactId> <version>3.8.5</version> <modules><module>ruoyi-admin</module><module>ruoyi-framework</module><module>…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

RocketMQ延迟消息机制
两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...

Ubuntu系统多网卡多相机IP设置方法
目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机,交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息,系统版本:Ubuntu22.04.5 LTS;内核版本…...