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

C#设计模式--策略模式(Strategy Pattern)

策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在策略模式定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换。通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需要修改客户端代码。

主要解决的问题

解决在多种相似算法存在时,使用条件语句(如if…else)导致的复杂性和难以维护的问题。

1. 定义策略接口

public interface IStrategy
{void Execute();
}

2. 实现具体策略

public class ConcreteStrategyA : IStrategy
{public void Execute(){Console.WriteLine("Executing strategy A");}
}public class ConcreteStrategyB : IStrategy
{public void Execute(){Console.WriteLine("Executing strategy B");}
}

3. 上下文类

public class Context
{private IStrategy _strategy;public Context(IStrategy strategy){_strategy = strategy;}public void SetStrategy(IStrategy strategy){_strategy = strategy;}public void ExecuteStrategy(){_strategy.Execute();}
}

类图

IStrategy
+void Execute()
ConcreteStrategyA
+void Execute()
ConcreteStrategyB
+void Execute()
Context
-IStrategy _strategy
+Context(IStrategy strategy)
+void SetStrategy(IStrategy strategy)
+void ExecuteStrategy()

用途

策略模式主要用于以下场景:
• 算法变化:当一个类的行为或其算法需要在运行时动态改变时。
• 多个算法变体:当有多个算法变体,并且需要在运行时选择其中一个时。
• 解耦:将算法的定义与使用算法的客户端解耦。

优点

  1. 灵活性:可以在运行时动态切换算法。
  2. 扩展性:增加新的策略非常容易,只需实现策略接口即可。
  3. 解耦:策略类和上下文类之间松耦合,符合开闭原则。

缺点

  1. 客户端复杂度:客户端必须了解所有策略类的区别,以便选择合适的策略。
  2. 增加对象数量:每个策略都是一个类,可能会导致类的数量增加。

实际开发中的应用举例

示例1:订单处理系统中的促销策略

假设一个订单处理系统,需要根据不同的促销策略,比如:没折扣、打折扣。也可以用是会员积分兑换,来计算订单的最终价格。

1. 定义促销策略接口

public interface IPromotionStrategy
{decimal ApplyPromotion(decimal originalPrice);
}

2. 实现具体的促销策略

public class NoDiscountStrategy : IPromotionStrategy
{public decimal ApplyPromotion(decimal originalPrice){return originalPrice; // 没有折扣}
}public class PercentageDiscountStrategy : IPromotionStrategy
{private readonly decimal _discountPercentage;public PercentageDiscountStrategy(decimal discountPercentage){_discountPercentage = discountPercentage;}public decimal ApplyPromotion(decimal originalPrice){return originalPrice * (1 - _discountPercentage / 100);//折扣}
}public class FixedAmountDiscountStrategy : IPromotionStrategy
{private readonly decimal _discountAmount;public FixedAmountDiscountStrategy(decimal discountAmount){_discountAmount = discountAmount;}public decimal ApplyPromotion(decimal originalPrice){return originalPrice - _discountAmount;}
}

3. 上下文类

public class Order
{private IPromotionStrategy _promotionStrategy;private decimal _originalPrice;public Order(decimal originalPrice, IPromotionStrategy promotionStrategy){_originalPrice = originalPrice;_promotionStrategy = promotionStrategy;}public void SetPromotionStrategy(IPromotionStrategy promotionStrategy){_promotionStrategy = promotionStrategy;}public decimal CalculateFinalPrice(){return _promotionStrategy.ApplyPromotion(_originalPrice);}
}

4. 使用示例

class Program
{static void Main(string[] args){// 创建订单,初始价格为100元,没有折扣var order = new Order(100, new NoDiscountStrategy());Console.WriteLine($"Original price: {order.CalculateFinalPrice()}");// 应用百分比折扣策略,折扣10%order.SetPromotionStrategy(new PercentageDiscountStrategy(10));Console.WriteLine($"Price after 10% discount: {order.CalculateFinalPrice()}");// 应用固定金额折扣策略,折扣20元order.SetPromotionStrategy(new FixedAmountDiscountStrategy(20));Console.WriteLine($"Price after fixed 20 discount: {order.CalculateFinalPrice()}");}
}

类图:

IPromotionStrategy
+decimal ApplyPromotion(decimal originalPrice)
NoDiscountStrategy
+decimal ApplyPromotion(decimal originalPrice)
PercentageDiscountStrategy
-decimal _discountPercentage
+PercentageDiscountStrategy(decimal discountPercentage)
+decimal ApplyPromotion(decimal originalPrice)
FixedAmountDiscountStrategy
-decimal _discountAmount
+FixedAmountDiscountStrategy(decimal discountAmount)
+decimal ApplyPromotion(decimal originalPrice)
Order
-IPromotionStrategy _promotionStrategy
-decimal _originalPrice
+Order(decimal originalPrice, IPromotionStrategy promotionStrategy)
+void SetPromotionStrategy(IPromotionStrategy promotionStrategy)
+decimal CalculateFinalPrice()

解释

  1. 定义促销策略接口:IPromotionStrategy 接口定义了一个 ApplyPromotion 方法,用于计算应用促销后的价格。
  2. 实现具体的促销策略:
    • NoDiscountStrategy:不应用任何折扣。
    • PercentageDiscountStrategy:应用百分比折扣。
    • FixedAmountDiscountStrategy:应用固定金额折扣。
  3. 上下文类:Order 类包含一个促销策略,并提供方法来设置促销策略和计算最终价格。
  4. 使用示例:创建一个订单,初始价格为100元,然后依次应用不同的促销策略,输出最终价格。

示例2:物流管理系统中的运输策略

假设一个物流管理系统,需要根据不同的运输方式(如快递、货运、空运等)来计算运费。也可以使用策略模式来实现这一点。

1. 定义运输策略接口

public interface ITransportStrategy
{decimal CalculateShippingCost(decimal weight, decimal distance);
}

2. 实现具体的运输策略

public class ExpressShippingStrategy : ITransportStrategy
{public decimal CalculateShippingCost(decimal weight, decimal distance){// 快递费用计算公式:重量 * 距离 * 0.5return weight * distance * 0.5m;}
}public class FreightShippingStrategy : ITransportStrategy
{public decimal CalculateShippingCost(decimal weight, decimal distance){// 货运费用计算公式:重量 * 距离 * 0.3return weight * distance * 0.3m;}
}public class AirShippingStrategy : ITransportStrategy
{public decimal CalculateShippingCost(decimal weight, decimal distance){// 空运费用计算公式:重量 * 距离 * 1.0return weight * distance * 1.0m;}
}

3. 上下文类

public class Shipment
{private ITransportStrategy _transportStrategy;private decimal _weight;private decimal _distance;public Shipment(decimal weight, decimal distance, ITransportStrategy transportStrategy){_weight = weight;_distance = distance;_transportStrategy = transportStrategy;}public void SetTransportStrategy(ITransportStrategy transportStrategy){_transportStrategy = transportStrategy;}public decimal CalculateTotalCost(){return _transportStrategy.CalculateShippingCost(_weight, _distance);}
}

4. 使用示例

class Program
{static void Main(string[] args){// 创建一个货物,重量为100公斤,距离为500公里,使用快递运输var shipment = new Shipment(100, 500, new ExpressShippingStrategy());Console.WriteLine($"Express Shipping Cost: {shipment.CalculateTotalCost()}");// 更改为货运运输shipment.SetTransportStrategy(new FreightShippingStrategy());Console.WriteLine($"Freight Shipping Cost: {shipment.CalculateTotalCost()}");// 更改为空运运输shipment.SetTransportStrategy(new AirShippingStrategy());Console.WriteLine($"Air Shipping Cost: {shipment.CalculateTotalCost()}");}
}

类图:

ITransportStrategy
+decimal CalculateShippingCost(decimal weight, decimal distance)
ExpressShippingStrategy
+decimal CalculateShippingCost(decimal weight, decimal distance)
FreightShippingStrategy
+decimal CalculateShippingCost(decimal weight, decimal distance)
AirShippingStrategy
+decimal CalculateShippingCost(decimal weight, decimal distance)
Shipment
-ITransportStrategy _transportStrategy
-decimal _weight
-decimal _distance
+Shipment(decimal weight, decimal distance, ITransportStrategy transportStrategy)
+void SetTransportStrategy(ITransportStrategy transportStrategy)
+decimal CalculateTotalCost()

解释

  1. 定义运输策略接口:ITransportStrategy 接口定义了一个 CalculateShippingCost 方法,用于计算运输费用。
  2. 实现具体的运输策略:
    • ExpressShippingStrategy:快递运输费用计算。
    • FreightShippingStrategy:货运运输费用计算。
    • AirShippingStrategy:空运运输费用计算。
  3. 上下文类:Shipment 类包含一个运输策略,并提供方法来设置运输策略和计算总费用。
  4. 使用示例:创建一个货物,初始运输方式为快递,然后依次更改为货运和空运,输出每种运输方式的费用。

优点

  1. 灵活性:可以在运行时动态切换促销策略。
  2. 扩展性:增加新的促销策略非常容易,只需实现 IPromotionStrategy 接口即可。
  3. 解耦:订单类和促销策略类之间松耦合,符合开闭原则。

缺点

  1. 客户端复杂度:客户端必须了解所有促销策略的区别,以便选择合适的策略。
  2. 增加对象数量:每个促销策略都是一个类,可能会导致类的数量增加。

相关文章:

C#设计模式--策略模式(Strategy Pattern)

策略模式是一种行为设计模式,它使你能在运行时改变对象的行为。在策略模式定义了一系列算法或策略,并将每个算法封装在独立的类中,使得它们可以互相替换。通过使用策略模式,可以在运行时根据需要选择不同的算法,而不需…...

【opencv入门教程】15. 访问像素的十四种方式

文章选自: 一、像素访问 一张图片由许多个点组成,每个点就是一个像素,每个像素包含不同的值,对图像像素操作是图像处理过程中常使用的 二、访问像素 void Samples::AccessPixels1(Mat &image, int div 64) {int nl imag…...

【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)

导航: 本文一些内容需要聚簇索引、非聚簇索引、B树、覆盖索引、索引下推等前置概念,虽然本文有简单回顾,但详细可以参考下文的【MySQL高级篇】 【Java笔记踩坑汇总】Java基础JavaWebSSMSpringBootSpringCloud瑞吉外卖/谷粒商城/学成在线设计模…...

根据html的段落长度设置QtextBrowser的显示内容,最少显示一个段落

要根据 HTML 段落的长度设置 QTextBrowser 的显示内容,并确保至少显示一个段落,可以通过以下步骤来实现: 加载 HTML 内容:首先,你需要加载 HTML 内容到 QTextBrowser 中。可以通过 setHtml() 方法来设置 HTML。 计算段…...

基于Huffman编码的GPS定位数据无损压缩算法

目录 一、引言 二、霍夫曼编码 三、经典Huffman编码 四、适应性Huffman编码 五、GPS定位数据压缩 提示:文末附定位数据压缩工具和源码 一、引言 车载监控系统中,车载终端需要获取GPS信号(经度、纬 度、速度、方向等)实时上传…...

php:完整部署Grid++Report到php项目,并实现模板打印

一、下载Grid++Report软件 路径:开发者安装包下载 - 锐浪报表工具 二、 安装软件 1、对下载的压缩包运行内部的exe文件 2、选择语言 3、 完成安装引导 下一步即可 4、接收许可协议 点击“我接受” 5、选择安装路径 “浏览”选择安装路径,点击"安装" 6、完成…...

C标签和 EL表达式的在前端界面的应用

目录 前言 常用的c标签有: for循环 1 表示 普通的for循环的 2 常在集合中使用 表示 选择关系 1 简单的表示如果 2 表示如果。。否则。。 EL表达式 格式 : ${属性名/对象/ 集合} 前言 本篇博客介绍 c标签和el表达式的使用 使用C标签 要引入 …...

Linux絮絮叨(四) 系统目录结构

Linux 系统的目录结构(Filesystem Hierarchy Standard, FHS)定义了 Linux 系统中文件系统的标准布局,以下是一些常见目录的功能: 根目录 / 描述:所有文件和目录的起始点,Linux 文件系统的根。内容&#xf…...

Java基于SpringBoot的网上订餐系统,附源码

博主介绍:✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&…...

《Java核心技术I》死锁

死锁 账户1:200元账户2: 300元线程1:从账号1转300到账户2线程2:从账户2转400到账户1 如上,线程1和线程2显然都被阻塞,两个账户的余额都不足以转账,两个线程都无法执行下去。 有可能会因为每一个线程要等…...

【Windows11系统局域网共享文件数据】

【Windows11系统局域网共享文件数据】 1. 引言1. 规划网络2. 获取必要的硬件3. 设置网络4. 配置网络设备5. 测试网络连接6. 安全性和维护7. 扩展和优化 2. 准备工作2.1: 启用网络发现和文件共享2.2: 设置共享文件夹 3. 访问共享文件夹4. 小贴士5. 总结 1. 引言 随着家庭和小型办…...

MCU、ARM体系结构,单片机基础,单片机操作

计算机基础 计算机的组成 输入设备、输出设备、存储器、运算器、控制器 输入设备:将其他信号转换为计算机可以识别的信号(电信号)。输出设备:将电信号(0、1)转为人或其他设备能理解的…...

在办公室环境中用HMD替代传统显示器的优势

VR头戴式显示器(HMD)是进入虚拟现实环境的一把钥匙,拥有HMD的您将能够在虚拟现实世界中尽情探索未知领域,正如如今的互联网一样,虚拟现实环境能够为您提供现实中无法实现的或不可能实现的事。随着技术的不断进步&#…...

ssm 多数据源 注解版本

application.xml 配置如下 <!-- 使用 DruidDataSource 数据源 --><bean id"primaryDataSource" class"com.alibaba.druid.pool.DruidDataSource" init-method"init" destroy-method"close"></bean> <!-- 使用 数…...

selenium常见接口函数使用

博客主页&#xff1a;花果山~程序猿-CSDN博客 文章分栏&#xff1a;测试_花果山~程序猿的博客-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们一起努力&#xff0c;一起成长&#xff01; 目录 1. 查找 查找方式 css_s…...

STM32F103单片机使用STM32CubeMX新建IAR工程步骤

打开STM32CubeMX软件&#xff0c;选择File 选择新建工程 在打开的窗口输入单片机型号 在右下角选择单片机型号&#xff0c;然后点右上角 start project&#xff0c;开始新建工程。 接下来设置调试接口&#xff0c;在左边System Core中选择 SYS&#xff0c;然后在右右边debu…...

刷题重开:找出字符串中第一个匹配项的下标——解题思路记录

问题描述&#xff1a; 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 示例 1&#xff1a; 输入&…...

product/admin/list?page=0size=10field=jancodevalue=4562249292272

文章目录 1、ProductController2、AdminCommonService3、ProductApiService4、ProductCommonService5、ProductSqlService https://api.crossbiog.com/product/admin/list?page0&size10&fieldjancode&value45622492922721、ProductController GetMapping("ad…...

人工智能机器学习无监督学习概念及应用详解

无监督学习&#xff1a;深入解析 引言 在人工智能和机器学习的领域中&#xff0c;无监督学习&#xff08;Unsupervised Learning&#xff09;是一种重要的学习范式。与监督学习不同&#xff0c;无监督学习不依赖于标签数据&#xff0c;而是通过模型从无标签的数据中学习数据的…...

APM装机教程(五):测绘无人船

文章目录 前言一、元生惯导RTK使用二、元厚HXF260测深仪使用三、云卓H2pro遥控器四、海康威视摄像头 前言 船体&#xff1a;超维USV-M1000 飞控&#xff1a;pix6c mini 测深仪&#xff1a;元厚HXF160 RTK&#xff1a;元生惯导RTK 遥控器&#xff1a;云卓H12pro 摄像头&#xf…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...

云原生安全实战:API网关Kong的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关&#xff08;API Gateway&#xff09; API网关是微服务架构中的核心组件&#xff0c;负责统一管理所有API的流量入口。它像一座…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配

目录 一、C 内存的基本概念​ 1.1 内存的物理与逻辑结构​ 1.2 C 程序的内存区域划分​ 二、栈内存分配​ 2.1 栈内存的特点​ 2.2 栈内存分配示例​ 三、堆内存分配​ 3.1 new和delete操作符​ 4.2 内存泄漏与悬空指针问题​ 4.3 new和delete的重载​ 四、智能指针…...