C++设计模式:策略模式(二)

1、定义与动机
  • 定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化),该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)

  • 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都硬编码到对象中,将会使对象变得异常复杂;而且有时候支持不适用的算法也是一个性能负担(代码段过长)

  • 如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?

2、举例
  • 对于一个跨境电商的软件来说计算不同国家的税收、货币结算是一个非常常见的事情
  • 而通产来说每个国家的税的计算方式并不相同,每个国家都有其自己的税换算算法
  • 这里的设计也存在一定的门路,如果换成代码层面来看
2.1、结构化软件设计流程

这种做法很简单:

  • 首先定义一个枚举类,将不同国家的税率计算方式定义出来(这个可以不需要)只是为了使用方便
  • 然后定义销售订单类,里面定义计算税的方法,具体的实现通过大量的if-else if-else来具体调用
  • 对于这样的一个计算税的方法,calculate方法过于庞大,主要存在两个问题:
    • 违背开闭原则(OCR):当这个海外电商需要新增一个上线的国家,那么需要修改TaxBase枚举类,其次需要在计算方法里面增加这个国家的税计算方式,很明显违背修改关闭拓展开放的原则
    • 性能负担:其实这个软件在一个国家上线后大量的其他国家的税计算方式并不关心,但是在代码中强行硬编码写入!运行起来的代码段充斥着大量的无关代码!导致性能的下降
enum TaxBase{CN_Tax,                 // 国内税US_Tax,                 // 美国税DE_Tax                  // 德国税/*如果需要增加,需要在这里继续枚举的定义....JP_Tax,FR_Tax*/
};class SalesOrder{
private:TaxBase tax;
public:double calculateTax(){//...if(tax == CN_Tax){// CN*****}else if(tax == US_Tax){// US*****}else if(tax == DE_Tax){// DE*****}// 这里需要增加拓展国家税的计算方式}
};
2.2、策略模式
  • 策略模式:当代码中存在大量的if-else if-else或者switch-case时,就应该考虑使用策略模式来优化
  • 实现思路思考:
    • 首先定义一个计算税的抽象基类TaxStrategy
    • 对于不同的国家计算方式定义不同的类继承TaxStrategy基类,并且实现其计算calculateTax方法
    • 然后在需要使用计算的代码中聚合/组合一个基类TaxStrategy的指针,如果注入的方式初始化!
    • 最后在需要的地方通过基类指针TaxStrategy调用对应的不同国家的方法。
    • 核心点主要有几地方:
      • 所有国家的税收计算类都继承基类,并且实现基类的抽象方法
      • 在需要使用的地方定义基类对象的指针,通过注入的方式传入需要的子类对象(多态)
      • 最后调用方法通过虚函数表来调用实际传入对象的计算方法(动态绑定、晚绑定)
      • 策略模式提倡的互相替换在这里通过多态来实现,替换体现在实际传入初始化的对象到底是哪一个!
  • 这样做的好处:
    • 如果需要增加新的国家,可以看到大部分代码都是不用修改的,只需要扩展新的类即可
    • 性能的优化,实际说在使用的过程中只需要把需要的对象new出来即可
class TaxStrategy {
public:virtual double calculateTax() = 0;virtual ~TaxStrategy();
};class CNTax: public TaxStrategy{
public:double calculateTax() override {// 国内税计算}
};class USTax: public TaxStrategy{
public:double calculateTax() override {// 美国税计算}
};class DETax: public TaxStrategy{
public:double calculateTax() override {// 德国税计算}
};
class JPTax: public TaxStrategy{
public:double calculateTax() override {// 日本税计算}
};class SalesOrder{
private:TaxStrategy *taxStrategy;               // 基类指针
public:SalesOrder(TaxStrategy *_taxStrategy): taxStrategy(_taxStrategy){}virtual ~SalesOrder(){delete taxStrategy;taxStrategy = nullptr;}double calculate(){// ...// 还是动态绑定通过虚函数来调用实际的传入对象的calculateTax方法double val = taxStrategy->calculateTax();// ...return val;}
};

在这里插入图片描述

通过这个UML图可以看到TaxStrategy和SalesOrder是相对稳定的,而不稳定的是TaxStrategy的子类

3、总结
  • Strategy及其子类为组件提供了一系列的可重用的算法,从而可以使得类型在运行时方便地根据需要再各个算法之间进行切换

  • Strategy模式提供了用条件判断语句意外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式

  • 如果Strategy对象没有实例化变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

autovacuum

相关查询语句 select relname,reltuples from pg_class where relnamepgbench_accounts; show autovacuum_vacuum_scale_factor ; select count(*) from pgbench_accounts; \dt pgbench_accounts SELECT * FROM pgstattuple(pgbench_accounts); --需要开启插件 SELECT relnam…

企业如何设计和实施有效的网络安全演练?

现实世界中,武装部队一直利用兵棋推演进行实战化训练,为潜在的军事冲突做准备。随着当今的数字化转型,同样的概念正在以网络安全演习的形式在组织中得到应用,很多企业每年都会基于合理的网络攻击场景和事件响应做一些测试和模拟。…

秋招学习数据库LeetCode刷题

数据库基本知识以前学过次数较多,今天看完一遍后都是可以理解的。直接刷Leetcode题吧 牛客上题库刷基础,Leetcode刷 写语句题(争取坚持每日2个sql语句题) 牛客:https://www.nowcoder.com/exam/intelligent?questionJobId10&tagId21015 L…

《QT实用小工具·十五》多种样式的开关控件

1、概述 源码放在文章末尾 目前实现了三种样式的开关控件按钮&#xff0c;如下所示&#xff1a; 项目部分代码如下所示&#xff1a; #ifndef IMAGESWITCH_H #define IMAGESWITCH_H/*** 图片开关控件 * 1. 自带三种开关按钮样式。* 2. 可自定义开关图片。*/#include <QWid…

分布式锁实战

4、分布式锁 4.1 、基本原理和实现方式对比 分布式锁&#xff1a;满足分布式系统或集群模式下多进程可见并且互斥的锁。 分布式锁的核心思想就是让大家都使用同一把锁&#xff0c;只要大家使用的是同一把锁&#xff0c;那么我们就能锁住线程&#xff0c;不让线程进行&#x…

鸿蒙实战开发-如何使用Stage模型卡片

介绍 本示例展示了Stage模型卡片提供方的创建与使用。 用到了卡片扩展模块接口&#xff0c;ohos.app.form.FormExtensionAbility 。 卡片信息和状态等相关类型和枚举接口&#xff0c;ohos.app.form.formInfo 。 卡片提供方相关接口的能力接口&#xff0c;ohos.app.form.for…

STM3定时器输入捕获、超声波测距

1、超声波测距模块介绍 1、HC-SR04共四个引脚&#xff1a;VCC、GND、Trig、Echo&#xff0c;如下图 2、使用 1、通过gpio口向Trig引脚发送一个脉冲信号。 2、HC-SR04接收到脉冲信号后&#xff0c;就会向外发送一段超声波&#xff0c;模块会将echo拉高。 …

Qt Creator 界面

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;QT❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、认识 Qt Creator 界面 1、总览 2、左边栏 3、代码编辑区 4、UI设计界面 5、构建区 一、认识 …

docker笔记(二):镜像、容器数据卷

四、 docker镜像 4.1 镜像 镜像是一种轻量级、可执行的独立软件包&#xff0c;用来打包软件运行环境和基于运行环境开发的软件&#xff0c;它包含运行某个软件所需的所有内容&#xff0c;包括代码、库、环境变量和配置文件 所有的应用&#xff0c;直接打包docker镜像就可以直…

每日一题(leetcode287):寻找重复数--二分查找+思维

思路&#xff1a;看官方解答 class Solution { public:int findDuplicate(vector<int>& nums) {int nnums.size();int left1;int rightn-1;int ans-1;while(left<right){int mid(leftright)/2;int count0;for(int j0;j<n;j){if(nums[j]<mid){count;}}if(co…

深度剖析扫雷游戏的各个知识点(1)

哈喽&#xff0c;小伙伴&#xff0c;大家好&#xff0c;今天我来水一篇文章。害&#xff0c;也不算真的水吧&#xff0c;这次带大家深度剖析初次写扫雷游戏程序时还未接触到的知识点。废话不多说&#xff0c;直接进入正题 不知小伙伴们是否还记得当时我说过扫雷游戏我们是以多个…

数据结构初阶:顺序表和链表

线性表 线性表 ( linear list ) 是 n 个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使 用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串 ... 线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性…