设计模式(二)

设计模式(二)

敏捷开发模式: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.mzph.cn/news/883549.shtml

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

相关文章

JVM(HotSpot):GC之G1垃圾回收器

文章目录 一、简介二、工作原理三、Young Collection 跨代引用四、大对象问题 一、简介 1、适用场景 同时注重吞吐量&#xff08;Throughput&#xff09;和低延迟&#xff08;Low latency&#xff09;&#xff0c;默认的暂停目标是 200 ms超大堆内存&#xff0c;会将堆划分为…

华为云弹性云服务器无法登录远程操作

遇到的问题&#xff1a; 就是你在创建弹性云服务器的时候选择了没有子网的虚拟私有云&#xff0c; 你属于误删了虚拟私有云的子网&#xff0c;自己没有注意看 如果在华为云创建弹性云服务器时选择的虚拟私有云&#xff08;VPC&#xff09;没有配置子网&#xff0c;那么在尝试远…

【mysql 进阶】2-1. MySQL 服务器介绍

MySQL 服务器简介 通常所说的 MySQL 服务器指的是mysqld程序&#xff0c;当运⾏mysqld后对外提供MySQL 服务&#xff0c;这个专题的内容涵盖了以下关于MySQL 服务器以及相关配置的内容&#xff0c;包括&#xff1a; 服务器⽀持的启动选项。可以在命令⾏和配置⽂件中指定这些选…

嵌入式C语言字符串具体实现

大家好,今天主要给大家分享一下,如何使用C语言进行字符串操作与实现。 第一:字符串相关操作实现 复制函数五个基本要素: 头文件:#include <string.h> 函数原型:strcpy(char dest[],char src[]) -----string copy 功能:把src数组中\0之前的所有字符,连同‘\…

在xml 中 不等式 做转义处理的问题

对于这种要做转义处理&#xff0c;<![CDATA[ < ]]>

讲一讲 kafka 的 ack 的三种机制?

大家好&#xff0c;我是锋哥。今天分享关于【K讲一讲 kafka 的 ack 的三种机制&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; 讲一讲 kafka 的 ack 的三种机制&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Kafka的消息确认机制&…

【计网】UDP Echo Server与Client实战:从零开始构建简单通信回显程序

目录 前言&#xff1a; 1.实现udpserver类 1.1.创建udp socket 套接字 --- 必须要做的 socket&#xff08;&#xff09;讲解 代码实现&#xff1a;​编辑 代码讲解&#xff1a; 1.2.填充sockaddr_in结构 代码实现&#xff1a; 代码解析&#xff1a; 1.3.bind sockfd和…

Vue2自定义指令及插槽

这里写目录标题 自定义指令基础语法指令的值封装v-loading指令 插槽默认插槽后备内容&#xff08;插槽的默认值&#xff09;具名插槽作用域插槽 自定义指令 自定义指令&#xff1a;自己定义的指令&#xff0c;封装一些dom操作&#xff0c;扩展额外功能 基础语法 全局注册&am…

2024年TI杯E题-三子棋游戏装置方案分享-jdk123团队-第四弹 第二题

往期回顾 前期准备 摄像头bug解决 手搓机械臂 视觉模块的封装 下面是题目部分&#xff1a; 第二问我们继续延续第一问的思路&#xff1a; 将棋子坐标与棋盘上标定的坐标进行绑定。 代码展示&#xff1a; import RPi.GPIO as GPIO import time import cv2 import numpy as…

【Qt】常用控件:按钮类控件

思维导图&#xff1a; 一、Push Button 我们可以使用 QPushButton 表示一个按钮&#xff0c;这也是当前我们最熟悉的一个控件。QPushButton继承于QAbstractButton。这个类是一个抽象类&#xff0c;是按钮的父类。 1.1 常用的属性 属性说明text按钮中的文本icon按钮中的图标ic…

Flutter登录界面使用主题

Now, let’s use the theme we initially created in our main function for a simple login screen: 现在&#xff0c;让我们使用最初在主函数中创建的主题来制作一个简单的登录屏幕&#xff1a; Create a Login Screen Widget: Inside the main.dartfile, create a new wid…

基于Springboot+Vue的候鸟监测数据管理系统 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 这个系…

MySQL 字段类型介绍

在 MySQL 中&#xff0c;设计数据库表时&#xff0c;需要根据数据的实际需求选择合适的数据类型&#xff0c;以确保数据存储的准确性和节省存储空间。MySQL 提供了丰富的字段类型&#xff0c;主要分为以下几类&#xff1a;数值类型、字符串类型、日期时间类型、和JSON类型等。 …

ffmpeg视频滤镜:定向模糊-dblur

滤镜简述 dblur 官网链接 > https://ffmpeg.org/ffmpeg-filters.html#dblur 有一个模糊滤镜&#xff0c;我试了一下&#xff0c;没有感觉到它的特殊之处, 这里简单介绍一下。 滤镜使用 滤镜的参数 angle <float> ..FV.....T. set angle (from 0 t…

019集——global全局引用报错解决方案(全局using指令在c#7.3中不可用)(CAD—C#二次开发入门)

如图&#xff0c;所示&#xff0c;全局引用global using出现报错&#xff1a; 解决方案如下&#xff1a; 新建一个类库&#xff0c;standard2.0版本。不要选.netframework 首先vs右下角更新vs版本 打开项目所在文件夹 找到项目文件.csproj&#xff0c;记事本打开。属性组位置加…

Go语言开发环境搭建

文档说明 本文作者:SwBack 创作时间:2022‎年‎6‎月‎8‎日 ‏‎18:46:21 知乎:https://www.zhihu.com/people/back-88-87 CSDN:https://blog.csdn.net/qq_30817059 百度搜索: SwBack系统: Windows 11 go 1.18.2 安装包下载 安装包下载链接 直接默认NEXT 查看Go版本 查看Go…

Coppelia Sim (v-REP)仿真 机器人3D相机手眼标定与实时视觉追踪 (二)

coppelia sim[V-REP]仿真实现 机器人于3D相机手眼标定与实时视觉追踪 二 zmq API接口python调用python获取3D相机的数据获取彩色相机的数据获取深度相机的数据用matpolit显示 python控制机器人运动直接控制轴的位置用IK运动学直接移动到末端姿态 相机内参的标定记录拍照点的位置…

Java面向对象编程高阶(一)

Java面向对象编程高阶&#xff08;一&#xff09; 一、关键字static1、static修饰属性2、静态变量与实例变量的对比3、static修饰方法4、什么时候将属性声明为静态的&#xff1f;5、什么时候将属性声明为静态的&#xff1f;6、代码演示 一、关键字static static用来修饰的结构…

Javaee---多线程(一)

文章目录 1.线程的概念2.休眠里面的异常处理3.实现runnable接口4.匿名内部类子类创建线程5.匿名内部类接口创建线程6.基于lambda表达式进行线程创建7.关于Thread的其他的使用方法7.1线程的名字7.2设置为前台线程7.3判断线程是否存活 8.创建线程方法总结9.start方法10.终止&…

VAE中的“变分”什么

写在前面 VAE&#xff08;Variational Autoencoder&#xff09;&#xff0c;中文译为变分自编码器。其中AE&#xff08;Autoencoder&#xff09;很好理解。那“变分”指的是什么呢?—其实是“变分推断”。变分推断主要用在VAE的损失函数中&#xff0c;那变分推断是什么&#x…