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

设计模式(二)

设计模式(二)

敏捷开发模式: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.mrgr.cn/news/59807.html

相关文章:

  • python psutil 模块概述
  • 【机器学习】——numpy教程
  • 第五章 nfs服务器
  • 【尊享面试100题】数组/字符串
  • Radar Fields: Frequency-Space Neural Scene Representations for FMCW Radar 笔记
  • vue3+vue-baidu-map-3x 实现地图定位
  • ROM修改进阶教程------简单通过指令来修改系统安全设置中选项的的开启或者关闭 内置指令在rom中的应用
  • 从零实现数据结构:一文搞定所有排序!(下集)
  • 网络文件系统nfs实验1
  • 基于neo4j关系图谱的协同过滤科研推荐系统
  • 工具方法 - Omnifocus: 网页版基本操作
  • 软考:软件建模的抽象级别
  • 解读AVL树:平衡二叉搜索树的奥秘
  • hdlbits系列verilog解答(DFF8-8位D触发器)-81
  • android openGL ES详解——缓冲区VBO/VAO/EBO/FBO/离屏渲染
  • 高速大容量还自带原厂数据恢复服务,希捷睿翼4TB移动硬盘评测
  • Python酷库之旅-第三方库Pandas(170)
  • css-画一个三角形
  • JavaFx -- chapter05(多用户服务器)
  • 基于Python的B站视频数据分析与可视化
  • 什么是环境变量?如何安装JAVA环境变量,实现命令行(cmd)执行java命令?win11、win10、win7一篇文章带你全部解决!包教包会!
  • 【论文笔记】Perceiver: General Perception with Iterative Attention
  • 【次小生成树】
  • 十八、【智能体】数据库:未来科技的大脑
  • word使用小技巧
  • 【MySQL】实战篇—应用开发:使用MySQL与编程语言(如Python、Java、PHP等)进行交互