策略模式【行为模式C++】

1.概述

策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。

策略模式通常应用于需要多种算法进行操作的场景,如排序、搜索、数据压缩等。在这些情况下,不同的算法有不同的优缺点和适用性,因此需要进行选择。

通过使用策略模式,我们可以轻松地切换算法,而无需修改客户端代码。这使得代码更加灵活、可扩展、易于维护,减少了重复的代码,并提高了代码的可读性。

2.结构

策略模式的结构包括以下几个部分:

抽象策略(Strategy)类:定义所有支持的算法或行为的公共接口或抽象类。
具体策略(Concrete Strategy)类:实现抽象策略接口,提供具体的算法或行为。
环境(Context)类:持有一个对抽象策略的引用,并且通过该引用调用具体策略类中实现的算法或行为。
在策略模式中,客户端代码仅与环境类及其抽象策略接口交互,无需关心具体实现细节。当需要更改算法或行为时,只需要修改具体策略类即可,而无需修改客户端代码或其他策略类。

3.实现

3.1 实例类比

假如你需要前往机场。 你可以选择乘坐公共汽车、 预约出租车或骑自行车。 这些就是你的出行策略。 你可以根据预算或时间等因素来选择其中一种策略。

3.2 实例引入

       在支付系统中,我们就可以使用策略模式,针对不同的支付方式封装成不同的策略类。每个策略类负责实现一个特定的支付方式,并提供相应的算法来处理付款。这样,客户端代码就可以通过选择不同的策略类来实现不同的支付方式,而无需了解每种支付方式的具体实现细节。

     例如,假设我们使用xx宝,可用银行卡、微信支付和支付宝支付三种支付方式。每种支付方式都有自己的实现方式和规则,但客户端并不需要知道支付方式的具体实现,只需要选择一个支付策略即可。这时候,我们可以使用策略模式来实现支付系统,将每种支付方式封装成一个支付策略类,让客户端根据需要选择不同的支付策略类。 

3.3  结构分析

   在这个案例中,代码中的各个结构可以对应到策略模式中的不同角色:

  • Context(上下文):对应代码中的PaymentContext类,负责调用具体支付策略对象的付款方法。
  • Strategy(策略):对应代码中的PaymentStrategy接口,定义了所有支持的支付方式的公共接口。
  • ConcreteStrategy(具体策略):对应代码中的BankCardStrategy、WeChatPayStrategy和AliPayStrategy类,实现了PaymentStrategy接口,提供了不同的支付方式实现逻辑。

类图如下:

3.4 具体实现
#include <iostream>
#include <string>

using namespace std;


//抽象策略
class PaymentStrategy {
public:
	virtual void pay(double money) = 0;
};

//具体策略
/**
 * 银联支付
 */
class BankCardStrategy :public PaymentStrategy {
private:
	/** 银行卡卡号 */
	string cardNumber;
	/** 银行卡有效期 */
	string expiryDate;
	
public:
	BankCardStrategy(string cardNumber, string expiryDate) {
		this->cardNumber = cardNumber;
		this->expiryDate = expiryDate;
	}
    
	void pay(double money) {
		// 基于卡的付款逻辑
		std::cout << "使用银联支付:"<< money <<"元" << endl;
	}
};

/**
 * 微信
 */
class WeChatPayStrategy :public PaymentStrategy {
private:
	/** 微信openId */
	string openId;

public:
	WeChatPayStrategy(string openId) {
		this->openId = openId;
	}

		void pay(double money) {
		// 基于微信支付的付款逻辑
	    std::cout << "使用微信支付:" << money << "元" << endl;
	}
};

/**
 * 支付宝
 */
class AliPayStrategy :public  PaymentStrategy {
private:
	string account;
	string password;

public:
	AliPayStrategy(string account, string password) {
		this->account = account;
		this->password = password;
	}

		 void pay(double money) {
		// 基于支付宝的付款逻辑
	    std::cout << "使用支付宝支付:" <<money << "元" << endl;
	}
};

class PaymentContext {
private:
	PaymentStrategy *_paymentStrategy;

public:
	void setPaymentStrategy(PaymentStrategy* paymentStrategy) {
		_paymentStrategy = paymentStrategy;
	}

    void pay(double money) {
		if (_paymentStrategy == nullptr) {
			throw std::runtime_error("支付策略不能为空");
		}
		_paymentStrategy->pay(money);
	}
};


int main()
{
	std::cout << "策略模式........" << endl;
	
	// 创建一个银联支付策略对象
	BankCardStrategy *bankCardStrategy = new BankCardStrategy("014600002206", "20224-12");
	// 创建一个微信支付策略对象
	WeChatPayStrategy *weChatPayStrategy = new WeChatPayStrategy("GoWJW");
	// 创建一个支付宝支付策略对象
	AliPayStrategy *aliPayStrategy = new AliPayStrategy("alipayaccount@gowjw.com", "alipaypassword");

	// 创建一个支付上下文对象
	PaymentContext *paymentContext = new PaymentContext();

	// 使用银联支付
	paymentContext->setPaymentStrategy(bankCardStrategy);
	paymentContext->pay(2024.4);

	// 使用微信支付
	paymentContext->setPaymentStrategy(weChatPayStrategy);
	paymentContext->pay(2024.4);

	// 使用支付宝支付
	paymentContext->setPaymentStrategy(aliPayStrategy);
	paymentContext->pay(2024.4);

	return 0;
}




3.5 运行结果 

4.策略优缺点

策略模式主要优点和缺点如下:

优点:

  • 策略模式使得各种算法可以在不修改原有代码的情况下替换或者新增,提高了代码的可扩展性和可维护性
  • 策略模式将算法的实现从上下文中解耦出来,使得算法可以独立进行单元测试;
  • 策略模式符合开闭原则,即对扩展开放,对修改关闭,可以通过增加新的策略类来扩展应用,而无需修改原有代码。

缺点:

  • 如果策略数量过多,会导致类数量增加,增加系统的复杂度
  • 客户端需要知道所有的策略类,并选择合适的策略类,这可能会导致客户端代码较为复杂;
  • 策略模式将算法的实现从上下文中解耦出来,同时也意味着上下文不能控制策略的执行顺序,需要客户端自行控制执行顺序。

5.应用场景

  • 系统需要动态地在几种算法中选择一种,或者根据不同的条件选择不同的算法;
  • 系统中有许多类似的行为,但是具体实现上有所不同,可以使用策略模式将这些行为抽象出来,并定义一个接口或抽象类,然后由具体的实现类来实现这个接口或抽象类;
  • 一些算法使用了相同的数据,但是实现上有所不同,可以使用策略模式来避免代码重复和代码膨胀,节省代码维护成本。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/543716.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++]C/C++的内存管理

这篇博客将会带着大家解决以下几个问题 1. C/C内存分布 2. C语言中动态内存管理方式 3. C中动态内存管理 4. operator new与operator delete函数 5. new和delete的实现原理 6. 定位new表达式(placement-new) 1. C/C内存分布 我们先来看下面的一段代码和相关问题 int global…

Unity 通过权重做随机

我们可以通过Random.Range方法结合权重来实现随机选择。具体步骤如下&#xff1a; 首先&#xff0c;创建一个数组&#xff0c;其中包含你要选择的项目&#xff0c;并为每个项目分配一个权重值。 计算所有权重值的总和。 使用Random.Range生成一个介于0和总权重之间的随机数。…

Hadoop+Spark大数据技术(微课版)曾国荪、曹洁版思维导图第四次作业 (第4章 HBase分布式DB)

1.简述Hbase的特点及与传统关系数据库的区别 HBase与传统关系数据库的区别 &#xff08;1&#xff09;数据类型 关系数据库具有丰富的数据类型&#xff0c;如字符串型、数值型、日期型、二进制型等。HBase只有字符串数据类型&#xff0c;数据的实际类型都是交由用户自己编写程序…

Google Imagen 2对比OpenAI的Dall-E 3 - 同一提示,不同结果

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

python怎么输出小数

先将整型转换成float型&#xff0c;再进行计算&#xff0c;结果就有小数了。 >>> a 10 >>> b 4 >>> c a/b >>> a,b,c (10, 4, 2) >>> a float(a) >>> d a/b >>> a,b,d (10.0, 4, 2.5) >>> 注意&…

1036: 寻找整数序列的主元素

解法&#xff1a; #include<iostream> #include<vector> #include<algorithm> using namespace std; int main() {int n;cin >> n;vector<int> arr(n);vector<int> tong(1000);for (auto& x : arr) {cin >> x;tong[x];}int pma…

如何在Windows安装LocalSend并结合内网穿透实现公网跨平台远程文件互传

文章目录 1. 在Windows上安装LocalSend2. 安装Cpolar内网穿透3. 公网访问LocalSend4. 固定LocalSend公网地址 本篇文章介绍在Windows中部署开源免费文件传输工具——LocalSend&#xff0c;并且结合cpolar内网穿透实现公网远程下载传输文件。 localsend是一款基于局域网的文件传…

宜搭无权查询该应用信息,唯一排查码:21081d4e17130865292352743e9ed8

这种问题可能是关联表单出现了问题&#xff0c;当前应用中没有这个表单 所以就出现了应用无权访问的问题

备战蓝桥杯(日益更新)(刷题)

备战蓝桥杯&#xff08;日益更新&#xff09;&#xff08;刷题&#xff09; 文章目录 备战蓝桥杯&#xff08;日益更新&#xff09;&#xff08;刷题&#xff09;前言&#xff1a;一、二分&#xff1a;1. acwing503 借教室&#xff1a;&#xff08;二分 差分&#xff09;2. ac…

荔枝派LicheePi 4A RISCV板子支持的好玩的AI模型

荔枝派LicheePi 4A 是基于 Lichee Module 4A 核心板的 高性能 RISC-V Linux 开发板&#xff0c;以 TH1520 为主控核心&#xff08;4xC9101.85G&#xff0c; RV64GCV&#xff0c;4TOPSint8 NPU&#xff0c; 50GFLOP GPU&#xff09;&#xff0c;板载最大 16GB 64bit LPDDR4X&…

JavaScript(七)-高级技巧篇

文章目录 深浅拷贝浅拷贝深拷贝 异常处理thorw抛异常try/catch捕获异常debugger 处理thisthis指向改变this 性能优化防抖lodash实现防抖手写防抖函数 节流 - throttle 深浅拷贝 浅拷贝 深拷贝 深拷贝有三种方式 通过递归实现深拷贝 一定先写数组再写对象 lodash/cloneDeep …

PostgreSQL入门到实战-第二十八弹

PostgreSQL入门到实战 PostgreSQL中数据分组操作(三)官网地址PostgreSQL概述PostgreSQL中GROUPING SETS命令理论PostgreSQL中GROUPING SETS命令实战更新计划 PostgreSQL中数据分组操作(三) 使用PostgreSQL grouping sets子句在查询中生成多个分组集。 官网地址 声明: 由于操…

[尚硅谷flink] 检查点笔记

在Flink中&#xff0c;有一套完整的容错机制来保证故障后的恢复&#xff0c;其中最重要的就是检查点。 文章目录 11.1 检查点11.1.1 检查点的保存1&#xff09;周期性的触发保存2&#xff09;保存的时间点3&#xff09;保存的具体流程 11.1.2 从检查点恢复状态11.1.3 检查点算法…

linux 内存寻址

&#xff08;持续更新&#xff09; 相关概念 查看的书籍为 深入linux内核 内存地址 当使用80x86&#xff08;32位&#xff09;微处理器时&#xff0c;一般分为三种不同的地址&#xff1a; 逻辑地址 包含在机器语言指令中用来指定一个操作数或一条指令的地址。每一个逻辑地址…

【服务器配置】Portainer环境配置

Portainer环境配置 概述 Portainer 是一种用于管理 Docker 和 Kubernetes 容器的开源工具。通过其用户友好的 Web 界面&#xff0c;用户可以轻松管理容器、镜像、网络和卷等资源 拉去最新的Portainer docker pull portainer/portainer 安装和启动 docker run -d --restarta…

WindowsServer 2022 AD域控-006-安装副域控

试验拓扑图&#xff1a; 一、测试单域控故障&#xff0c;用户无法修改密码&#xff1b; 域控断网&#xff0c;Win10测试; 二、WindowsServer2022 DC02加入域控&#xff1b; 加入成功 此时域控上只有DC02这台服务器&#xff0c;但DC02并不是域控&#xff1b; 三、WindowsS…

『VUE』17. Dom与模板引用(详细图文注释)

目录 回顾之前的操作ref 属性借助dom使用原生js总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 回顾之前的操作 之前的这些操作都是我们使用vue为我们渲染的对象,再来操作dom 内容改变{{ 模板语法 }}属性改变 v-bind:添加事…

Java 中文官方教程 2022 版(二十九)

原文&#xff1a;docs.oracle.com/javase/tutorial/reallybigindex.html BCP 47 扩展 原文&#xff1a;docs.oracle.com/javase/tutorial/i18n/locale/extensions.html Java SE 7 版本符合 IETF BCP 47 标准&#xff0c;支持向Locale添加扩展。任何单个字符都可以用于表示扩展&…

2. Spring的创建和Bean的存取

经过前面的学习我们已经大体明白了 IOC 思想以及它的实现方式 DI &#xff0c;本节要讲的是如何Spring框架实现实现DI。 本节目标&#xff1a; Spring(Core) 项目创建将对象存储到 Spring 中将对象(bean)从 Spring 中取出 1. 创建 Spring 项目 与开篇演示的 Spring Boot 项目不…

2024MathorCup数学建模B题成品论文26页+1-4小问代码全解析+答疑

B题 甲骨文智能识别中原始拓片单字自动分割与识别研究 &#xff08;完整版见文末&#xff09; 甲骨文是我国目前已知的最早成熟的文字系统&#xff0c;它是一种刻在龟甲或兽骨上的古老文字。甲骨文具有 极其重要的研究价值&#xff0c;不仅对中国文明的起源具有重要意义&#x…