设计模式(二)

设计模式(二)

敏捷开发模式:Refactoring to Patterns

重构特点:

1. 静态 --------> 动态
1. 早绑定 -----------> 晚绑定
1. 继承 ----------> 组合
1. 编译时依赖 --------> 运行时依赖
1. 紧耦合 -------> 松耦合

组件协作模式

通过晚期绑定,实现框架和应用间的松耦合

  1. Template Method
  2. Strategy
  3. Observer / Event
tips:基类的析构函数需要写为 虚析构函数
why:1.析构函数的作用是清理对象占用的资源;当对象生命周期结束时,析构函数会被自动调用2.为了确保当通过基类指针删除派生类对象时,能够正确地调用派生类的析构函数,从而避免资源泄漏3.多态:基类指针可以指向派生类的对象;使用基类指针删除指向的派生类对象时,如果基类的析构函数不是虚的那么只会调用基类的析构函数,而不会调用派生类的析构函数派生类可能有自己的资源需要释放,比如动态分配的内存或者打开的文件,没有正确释放,就会造成资源的泄露4.C++中对象的析构顺序是先调用派生类的析构函数,然后调用基类的析构函数如果基类的析构函数是虚的,那么当删除一个派生类对象时,首先会调用派生类的析构函数,然后是基类的析构函数
Template Method

定义一个操作中的算法的骨架(稳定), 而将一些步骤延迟(变化)到子类中

Template Method设计子类可以不改变(复用)一个算法的结构

即可重定义(override)该算法的某些步骤

// 抽象类
class Shape {
public:// 模板方法,定义了绘制图形的算法骨架void draw() {drawShape();fillShape();}// 抽象操作,由子类实现virtual void drawShape() = 0;virtual void fillShape() = 0;
};// 具体子类
class Rectangle : public Shape {
public:// 实现抽象操作void drawShape() override {// 绘制矩形的轮廓}void fillShape() override {// 填充矩形}
};class Circle : public Shape {
public:// 实现抽象操作void drawShape() override {// 绘制圆的轮廓}void fillShape() override {// 填充圆}
};

上述draw()是稳定的,不用虚函数

drawShape(), fillShape() 绘制图像,有圆的,有方的等

这是变化的,定义为虚函数;

这样就实现,算法的骨架(draw()) (稳定),变化(drawShape, fillShape)变化延迟到子类中

假设类中所有的都是稳定的,就不需要设计模式
假设类中所有都不是稳定的,也不需要设计模式了

设计模式 就是在变化和稳定中间,寻找隔离点,将变化和稳定隔离开

tips:查看代码时,找到类中哪些是变化的哪些是稳定的
这种晚绑定,c++通常用多态实现;
其实多态底层也是用函数指针实现
Strategy

motivation

软件构建中,某些对象使用的算法可能多种多样;经常改变

假设这些算法都编码到对象中,将使对象变得异常复杂;

how to 运行时根据需要透明地更改对象的算法? 实现算法和对象本身解耦合

需要用动态的思维去思考问题,设计解决方案,考虑未来;

如果使用静态的思维,只考虑当前问题,无法设计出好的方案应对未来的变化

用扩展的方式来改变;而不是修改来改变源代码

eg:使用枚举(enum)来定义不同的税率策略,然后使用if-else语句来选择相应的税率计算方法

enum TaxCountry {CHINA,USA,GERMANY
};double calculateTax(double income, TaxCountry country) {switch (country) {case CHINA:return income * 0.2;case USA:return income * 0.3;case GERMANY:return income * 0.25;default:return 0;}
}

策略模式:创建一个TaxStrategy接口,将上面的每个case实例,定义为该接口的子类

class TaxStrategy {
public:virtual ~TaxStrategy() {}virtual double calculateTax(double income) = 0;
};// 具体策略:中国税率
class ChinaTaxStrategy : public TaxStrategy {
public:double calculateTax(double income) override {return income * 0.2;}
};// 具体策略:美国税率
class USATaxStrategy : public TaxStrategy {
public:double calculateTax(double income) override {return income * 0.3;}
};// 具体策略:德国税率
class GermanyTaxStrategy : public TaxStrategy {
public:double calculateTax(double income) override {return income * 0.25;}
};// 上下文
class IncomeCalculator {
private:std::unique_ptr<TaxStrategy> taxStrategy;public:void setTaxStrategy(std::unique_ptr<TaxStrategy> taxStrategy) {this->taxStrategy = std::move(taxStrategy);}double calculateIncomeTax(double income) {return taxStrategy->calculateTax(income);}
};int main() {double income = 10000;IncomeCalculator calculator;// 假设我们选择中国税率和美国税率calculator.setTaxStrategy(std::make_unique<ChinaTaxStrategy>());std::cout << "Income tax for China: " << calculator.calculateIncomeTax(income) << std::endl;calculator.setTaxStrategy(std::make_unique<USATaxStrategy>());std::cout << "Income tax for USA: " << calculator.calculateIncomeTax(income) << std::endl;return 0;
}

定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化);

该模式使得算法可独立于使用它的客户程序(稳定) 而变化 (扩展,子类化)

if - else if 或 switch case; 通常都用策略模式来做接口; 只有那些固定下来的条件,不会再变了可以使用

而且用switch case ,if else在运行时内存装载也会出现问题,造成内存臃肿

observe

motivation

软件构建过程中,需要为某些对象建立一种 通知依赖关系

即:一个对象(观察者)的状态发生改变,所有的依赖对象(观察者对象)都会得到通知

如果这样,依赖关系过于紧密,将使软件不能很好地抵御变化

使用面向对象,将这种依赖关系弱化,形成一种稳定的依赖关系,从而实现软件体系结构的松耦合

新闻订阅服务为例,

class NewsService {
public:void addNews(std::string news) {// 添加新闻for (auto user : users) {user->notify(news); // 直接调用每个用户的notify方法}}private:std::vector<User*> users; // 紧密耦合的用户列表
};class User {
public:void notify(std::string news) {// 用户接收到新闻更新}
};
NewsService类与User类紧密耦合,如果需要添加新的用户类型或者改变通知方式,需要修改NewsService类的代码
扩展性差,如果未来有新的通知方式,例如邮件通知、短信通知等,需要在NewsService类中添加更多的代码

通过一个抽象的接口进行交互

class Subject {
public:virtual void registerObserver(Observer* observer) = 0;virtual void removeObserver(Observer* observer) = 0;virtual void notifyObservers(std::string news) = 0;
};class Observer {
public:virtual void update(std::string news) = 0;
};class NewsService : public Subject {
private:std::vector<Observer*> observers;public:void registerObserver(Observer* observer) override {observers.push_back(observer);}void removeObserver(Observer* observer) override {// 移除观察者}void notifyObservers(std::string news) override {for (auto observer : observers) {observer->update(news);}}void addNews(std::string news) {notifyObservers(news); // 通知所有观察者}
};class User : public Observer {
public:void update(std::string news) override {// 用户接收到新闻更新}
};
可扩展性:可以轻松地添加新的观察者类型,例如添加一个新的User子类来处理不同类型的用户
可维护性:由于解耦,修改NewsService或User类时,对其他类的依赖更少,因此更容易维护
灵活性:可以动态地添加或移除观察者,而不需要修改NewsService类的内部实现

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

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

相关文章

spark on kubernetes运行测试

测试环境 ● kubernetes 1.20.15 ● default命名空间 ● spark 3.1.2 ● kubectl 运行架构 构建镜像 配置JAVA_HOME下载spark二进制包spark-3.1.2-bin-hadoop3.2.tgz并解压修改kubernetes/dockerfiles/spark/Dockerfile文件 ARG java_image_tag11-jre-slimFROM openjdk:${j…

HBuilder X 中Vue.js基础使用2(三)

一、条件渲染 1、条件判断 v-if &#xff1a; 表达式返回真值时才被渲染 v-else &#xff1a;表达式返回为假时不被渲染 2、 分支条件判断 v-else-if &#xff1a;使用v-if , v-else-if 和 v-else 来表示其他的条件分支 3、显示隐藏 v-show v-show true 把节点显示 …

持续深化信创布局,途普科技与统信软件完成产品兼容性互认证

近日&#xff0c;由北京途普科技有限公司&#xff08;以下简称“途普科技”&#xff09;自主研发的TopGraph图数据库及知识图谱构建平台已成功完成统信服务器操作系统V20的兼容性互认证&#xff0c;标志着途普科技在国产自控技术上又迈出了坚实的一步。 在各项严格的测试环节中…

技术成神之路:设计模式(二十一)外观模式

相关文章&#xff1a;技术成神之路&#xff1a;二十三种设计模式(导航页) 介绍 外观模式&#xff08;Facade Pattern&#xff09;是一种结构型设计模式&#xff0c;它为子系统中的一组接口提供一个统一的接口。外观模式定义了一个高层接口&#xff0c;使得子系统更容易使用。 …

XJ02、消费金融|消费金融业务模式中的主要主体

根据所持有牌照类型的不同,消费金融服务供给方主要分为商业银行、汽车金融公司、消费金融公司和小贷公司,不同类型机构定位不同、提供消费金融服务与产品类型也各不相同。此外,互联网金融平台也成为中国消费金融业务最重要的参与方之一,虽其并非持牌金融机构,但借助其流量…

D50【python 接口自动化学习】- python基础之类

day50 init方法 学习日期&#xff1a;20241027 学习目标&#xff1a;类 -- 64 init方法&#xff1a;如何为对象传递参数&#xff1f; 学习笔记&#xff1a; 魔术方法 init方法 class Klass(object):# 定义初始化方法&#xff0c;类实例化时自动进行初始化def __init__(self…

AGI 之 【Dify】 之 Dify 在 Windows 端本地部署调用 Ollama 本地下载的大模型,实现 API 形式进行聊天对话

AGI 之 【Dify】 之 Dify 在 Windows 端本地部署调用 Ollama 本地下载的大模型&#xff0c;实现 API 形式进行聊天对话 目录 AGI 之 【Dify】 之 Dify 在 Windows 端本地部署调用 Ollama 本地下载的大模型&#xff0c;实现 API 形式进行聊天对话 一、简单介绍 二、创建一个聊…

基于SSM+小程序的旅游社交登录管理系统(旅游4)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 ​ 本旅游社交小程序功能有管理员和用户。管理员有个人中心&#xff0c;用户管理&#xff0c;每日签到管理&#xff0c;景点推荐管理&#xff0c;景点分类管理&#xff0c;防疫查询管理&a…

洞察前沿趋势!2024深圳国际金融科技大赛——西丽湖金融科技大学生挑战赛技术公开课指南

在当前信息技术与“互联网”深度融合的背景下&#xff0c;金融行业的转型升级是热门话题&#xff0c;创新与发展成为金融科技主旋律。随着区块链技术、人工智能技术、5G通信技术、大数据技术等前沿科技的飞速发展&#xff0c;它们与金融领域的深度融合&#xff0c;正引领着新型…

Golang 怎么高效处理ACM模式输入输出

文章目录 问题bufio.NewReader高效的原理 再次提交 问题 最近在练习牛客上单调栈题目时&#xff0c;要求自己处理出入输出&#xff0c;也就是读题库要求的输入&#xff0c;计算最终结果&#xff0c;并打印输出 当我用fmt.Scan处理输入&#xff0c;用fmt.Println处理输出时&am…

R语言笔记(五):Apply函数

文章目录 一、Apply Family二、apply(): rows or columns of a matrix or data frame三、Applying a custom function四、Applying a custom function "on-the-fly"五、Applying a function that takes extra arguments六、Whats the return argument?七、Optimized…

linux开机自启动三种方式

方式一、 1&#xff1a;rc.local 文件 1、执行命令&#xff1a;编辑 “/etc/rc.local” vi /ect/rc.local 2、然后在文件最后一行添加要执行程序的全路径。 例如&#xff0c;每次开机时要执行一个 hello.sh&#xff0c;这个脚本放在 / usr 下面&#xff0c;那就可以在 “/et…

深入了解 Android 中的命名空间:`xmlns:tools` 和其他常见命名空间

在 Android 开发中&#xff0c;xmlns &#xff08;.xml的namespace&#xff09;命名空间是一个非常重要的概念。通过引入不同的命名空间&#xff0c;可以使用不同的属性来设计布局、设置工具属性或者支持自定义视图等。除了 xmlns:tools 以外&#xff0c;还有很多常见的命名空间…

动态IP是什么?

随着互联网成为人们生活的重要组成部分&#xff0c;以信息传递为主导的时代种&#xff0c;网络连接质量对我们的工作效率、学习进度以及娱乐体验等方面都有很大影响。 动态IP&#xff0c;作为网络连接中的一种重要IP代理形式&#xff0c;越来越受到用户的欢迎。本文将深入解析…

计算机网络-CSMA/CD协议笔记及“争用期”的理解

假设a和b是总线型网络上相距最远的两个节点。 从零这个时刻a节点会往信道上发送数据&#xff0c;那么a节点发送的第一个比特&#xff0c;需要经过τ这么长的时间&#xff0c;也就是经过一个单向的传播时延之后。它的这个信号才可以被最远的这个节点检测到。那如果b结点在τ这个…

以bat脚本实现自动识别盘符名称

以bat脚本实现自动识别盘符名称 引言以bat脚本实现自动识别盘符名称运行结果 引言 请听题&#xff0c;如何自动识别电脑盘符的名称&#xff0c;比如&#xff0c;F盘的盘符名称为office&#xff0c;我应该如何自动识别呢&#xff1f; 这里我是以bat脚本实现 以bat脚本实现自动…

平均误差ME、均方误差MSE、均方根误差RMSE、平均均方根误差ARMSE辨析

四个性能指标的定义和作用的解释 ME(k) - 平均误差(Mean Error) 公式: M E ( k ) = ( 1 / M ) ∗ Σ ( x k − x ^ k ) , m = 1 , . . . , M ME(k) = (1/M) * Σ(xk - x̂k), m = 1, ..., M ME(k)=(1/M)∗Σ(xk−

VUE3实现古典音乐网站源码模板

文章目录 1.设计来源1.1 网站首页页面1.2 古典音乐页面1.3 著名人物页面1.4 古典乐器页面1.5 历史起源页面1.6 登录页面1.7 注册页面 2.效果和源码2.1 动态效果2.2 目录结构 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xc…

【Unity踩坑】UWP应用未通过Windows应用认证:API不支持

在将Unity项目导出为XAML类型的UWP项目后&#xff0c;通过Visual Studio打包成功&#xff0c;但在进行Windows应用认证时结果是Failed。 其中的错误是某些dll里用到了Windows SDK不支持的API。 本次问题中涉及到的具体dll有两个&#xff1a;gilzoide-sqlite-net.dll和D3D12Cor…

排序

插入排序&#xff08;最有价值&#xff09; 类似于摸牌 InsertSort&#xff1a;O(N^2)&#xff1b;最好&#xff1a;O(N) 最坏情况&#xff1a;逆序有序 最好情况&#xff1a;O(N)顺序有序 比冒泡排序实际应用更高效 以下是单趟排序&#xff0c;实现多趟需要再嵌套一个fo…