C++ 创建型设计模式

news2024/11/15 22:51:37

何为设计模式

设计模式是指在软件开发中,经过验证的,用于解决在特定环
境下,重复出现的,特定问题的解决方案;

设计原则

依赖倒置
在这里插入图片描述
开放封闭
一个类应该对扩展(组合和继承)开放,对修改关闭;
面向接口
不将变量类型声明为某个特定的具体类,而是声明为某个接口;客户程序无需获知对象的具体类型,只需要知道对象所具有的接口;
减少系统中各部分的依赖关系,从而实现“高内聚、松耦合”的类型设计方案;
封装变化点
将稳定点和变化点分离,扩展修改变化点;让稳定点和变化点的实现层次分离;
单一职责
一个类应该仅有一个引起它变化的原因;
里氏替换
子类型必须能够替换掉它的父类型;主要出现在子类覆盖父类实现,原来使用父类型的程序可能出现错误;覆盖了父类方法却没有实现父类方法的职责;
接口隔离
不应该强迫客户依赖于它们不用的方法;
一般用于处理一个类拥有比较多的接口,而这些接口涉及到很多职责;
客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上。
组合优于继承
继承耦合度高,组合耦合度低;

模板方法

要点

  • 最常用的设计模式,子类可以复写父类子流程,使父类的骨架流
    程丰富;
  • 反向控制流程的典型应用;
  • 父类 protected 保护子类需要复写的子流程;这样子类的子流程
    只能父类来调用;

案例理解
某个品牌动物园,有一套固定的表演流程,但是其中有若干个表演子流程可创新替换,以尝试迭代更新表演流程;
变化点:子任务迭代,稳定点:父类骨架不变即对外接口不变

#include <iostream>
using namespace std;

// 开闭
class ZooShow {
public:
    void Show() {
        // 如果子表演流程没有超时的话,进行一个中场游戏环节;如果超时,直接进入下一个子表演流程
        if (Show0())
            PlayGame();
        Show1();
        Show2();
        Show3();
    }
    
private:
    void PlayGame() {
        cout << "after Show0, then play game" << endl;
    }
    bool expired;
    // 对其他用户关闭,但是子类开放的
protected:
    virtual bool Show0() {
        cout << "show0" << endl;
        if (! expired) {
            return true;
        }
        return false;
    }
    virtual void Show2() {
        cout << "show2" << endl;
    }
    virtual void Show1() {

    }
    virtual void Show3() {

    }
};

// 框架
// 模板方法模式
class ZooShowEx10 : public ZooShow {
protected:
    virtual void Show0() {
        if (! expired) {
            return true;
        }
        return false;
    }
}

class ZooShowEx1 : public ZooShow {
protected:
    virtual bool Show0() {
        cout << "ZooShowEx1 show0" << endl;
        if (! expired) { // 里氏替换
            return true;
        }
        return false;
    }
    virtual void Show2(){
        cout << "show3" << endl;
    }
};

class ZooShowEx2 : public ZooShow {
protected:
    virtual void Show1(){
        cout << "show1" << endl;
    }
    virtual void Show2(){
        cout << "show3" << endl;
    }
};

class ZooShowEx3 : public ZooShow {
protected:
    virtual void Show1(){
        cout << "show1" << endl;
    }
    virtual void Show3(){
        cout << "show3" << endl;
    }
    virtual void Show4() {
        //
    }
};
/*
*/
int main () {
    ZooShow *zs = new ZooShowEx10; // 晚绑定还是早绑定
    // ZooShow *zs1 = new ZooShowEx1;
    // ZooShow *zs2 = new ZooShowEx2;
    zs->Show();
    return 0;
}

观察者模式

定义
定义对象间的一种一对多(变化)的依赖关系,以便当一个对
象(Subject)的状态发生改变时,所有依赖于它的对象都得到通
知并自动更新。 ——《 设计模式》 GoF
要点

  • 观察者模式使得我们可以独立地改变目标与观察者,从而使二者
    之间的关系松耦合;
  • 观察者自己决定是否订阅通知,目标对象并不关注谁订阅了;
  • 观察者不要依赖通知顺序,目标对象也不知道通知顺序;
  • 常用在基于事件的ui框架中,也是 MVC /QT的组成部分;
  • 常用在分布式系统中、actor框架中;
    应对稳定点,抽象
    应对变化点,扩展(继承和组合)
    本质
    触发联动
    代码背景
    气象站发布气象资料给数据中心,数据中心经过处理,将气象
    信息更新到两个不同的显示终端(A 和B);
    在这里插入图片描述
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
//
class IDisplay {
public:
    virtual void Show(float temperature) = 0;
    virtual ~IDisplay() {}
};

class DisplayA : public IDisplay {
public:
    virtual void Show(float temperature) {
        cout << "DisplayA Show" << endl;
    }
private:
    void jianyi();
};

class DisplayB : public IDisplay{
public:
    virtual void Show(float temperature) {
        cout << "DisplayB Show" << endl;
    }
};

class DisplayC : public IDisplay{
public:
    virtual void Show(float temperature) {
        cout << "DisplayC Show" << endl;
    }
};

class DisplayD : public IDisplay{
public:
    virtual void Show(float temperature) {
        cout << "DisplayC Show" << endl;
    }
};

class WeatherData {
};

// 应对稳定点,抽象
// 应对变化点,扩展(继承和组合)
class DataCenter {
public:
    void Attach(IDisplay * ob) {
        //
    }
    void Detach(IDisplay * ob) {
        //
    }
    void Notify() {
        float temper = CalcTemperature();
        for (auto &ob : obs) {
            ob->Show(temper);
        }
    }

// 接口隔离
private:
    WeatherData * GetWeatherData();

    float CalcTemperature() {
        WeatherData * data = GetWeatherData();
        // ...
        float temper/* = */;
        return temper;
    }
    std::list<IDisplay*> obs;
};

int main() {
    // 单例模式
    DataCenter *center = new DataCenter;
    // ... 某个模块
    IDisplay *da = new DisplayA();
    center->Attach(da);

    // ...
    IDisplay *db = new DisplayB();
    center->Attach(db);
    
    IDisplay *dc = new DisplayC();
    center->Attach(dc);

    center->Notify();
    
    //-----
    center->Detach(db);
    center->Notify();

    center->Notify();
    return 0;
}

策略模式

定义
定义一系列算法,把它们一个个封装起来,并且使它们可互相
替换。该模式使得算法可独立于使用它的客户程序而变化。
——《设计模式》 GoF
要点
策略模式提供了一系列可重用的算法,从而可以使得类型在运行
时方便地根据需要在各个算法之间进行切换;
策略模式消除了条件判断语句;也就是在解耦合;
本质
分离算法,选择实现;
在这里插入图片描述
代码背景
某商场节假日有固定促销活动,为了加大促销力度,现提升国
庆节促销活动规格;

class Context {

};

// 稳定点:抽象去解决它
// 变化点:扩展(继承和组合)去解决它
class ProStategy {
public:
    virtual double CalcPro(const Context &ctx) = 0;
    virtual ~ProStategy(); 
};
// cpp
class VAC_Spring : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){
    }
};

class VAC_Spring_v2 : public VAC_Spring {
public:
    virtual double CalcPro(const Context &ctx){
        //....
    }
};

class VAC_worker : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};

// cpp
class VAC_QiXi : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};
class VAC_QiXi1  : public VAC_QiXi {
public:
    virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_Wuyi : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};
// cpp
class VAC_GuoQing : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};
class VAC_GuoQing2 : public VAC_GuoQing {
public:
    virtual double CalcPro(const Context &ctx){}
};

class VAC_Shengdan : public ProStategy {
public:
    virtual double CalcPro(const Context &ctx){}
};

// 设计原则:接口隔离原则
// 组合、继承
// 组合基类指针
// 两种方法:1. 采用具体接口选择算法  2. 依赖注入
class Promotion {
public:
    Promotion(ProStategy *sss = nullptr) : s(sss){}
    ~Promotion(){}
    void Choose(ProStategy *sss) {
        // 条件选择
        if (sss != nullptr) {
            s = sss;
        }
    }
    double CalcPromotion(const Context &ctx){
        if (s != nullptr) {
            return s->CalcPro(ctx);
        }
        return 0.0L;
    }
private:
    ProStategy *s;
};

int main () {
    Context ctx;
    ProStategy *s = new VAC_QiXi1();  //算法:变化
    Promotion *p = new Promotion(s);  //促销活动:稳定
    p->Choose(new VAC_GuoQing2());
    p->CalcPromotion(ctx);
    return 0;
}

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

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

相关文章

犀牛检测系统源码分享

犀牛检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vision …

N诺计算机考研-错题

B A.LLC,逻辑链路控制子层。一个主机中可能有多个进程在运行,它们可能同时与其他的一些进程(在同一主机或多个主机中)进行通信。因此在一个主机的 LLC子层的一个服务访问点,以便向多个进程提供服务。B.MAC地址,称为物理地址、硬件地址,也称为局域网地址,用来定义网络设…

python与html链接测试

做这个测试我使用了两个资源 1.csdn上收集的参考资料&#xff0c;特此感谢 链接如下&#xff1a;Pycharm社区版创建Flask项目(配置项目文件)_pycharm community flask-CSDN博客 2.kimi 网址如下&#xff1a;Kimi.ai - 帮你看更大的世界 (moonshot.cn) 这是试出来的操作步骤…

python如何查看文件的目录

1、sys.arg[0]: import sys print(sys.argv[0])#当前脚本的位置 输出结果&#xff1a; G:/Pythonxx/test.py 2、os模块 import os print("1111") print (os.getcwd())#获得当前目录 print (os.path.abspath(.))#获得当前工作目录 print (os.path.abspath(..))#获得当…

基于丹摩智算部署可图(Kolors)

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;Linux从入门到进阶 欢迎大家点赞收藏评论&#x1f60a; 目录 丹摩智算平台简介一、Kolors 简介介绍技术背景部署与使用前提条件 二、DAMODEL 平台创建适配机器1.1、实例创建 三、服务部署安装 An…

性能测试利器 - Locust框架解析

01 认识Locust 说起性能测试工具&#xff0c;大家肯定想到的都是Jmeter&#xff0c;是的&#xff0c;由于其简单易用、功能强大&#xff0c;已经变成主流的压测工具之一。当需要实现一些高级功能的时候&#xff0c;可以使用Java语言对Jmeter进行扩展。 但是很多小伙伴只会Pyt…

10种数据库技术的发展历程与现状

数据库是互联网的基石&#xff0c;存储着海量信息&#xff0c;使信息可被高效地组织、检索和分享。没有数据库&#xff0c;网站无法记忆用户数据&#xff0c;应用无法提供个性化服务&#xff0c;信息交流将失去智能与连贯性。因此&#xff0c;数据库技术极大地推动了互联网的发…

如何使用 Windows 自带的虚拟机 Hyper-V

当前环境: Windows 10 Pro 开启 Hyper-V 功能 开启 Hyper-V 功能 开始菜单, 搜索 “control” 打开控制面板点击 “程序” > “启用或关闭 Windows 功能”开启所有的 Hyper-V 选项 安装虚拟机 准备系统镜像 .iso 文件 进入 itellyou.cn 进行下载所需镜像我选择的是: Wind…

nginx部署手册

1、在安装nginx前首先要确认系统中安装了gcc、pcre-devel、zlib-devel、openssl-devel yum -y install gcc pcre-devel zlib-devel openssl openssl-devel2、 新建nginx用户 &#xff08;1&#xff09;groupadd 命令用于创建一个新的用户组 groupadd nginx&#xff08;2&#…

鸿蒙开发(NEXT/API 12)【基础功能(EnterpriseAdminExtensionAbility开发指南)】企业设备管理服务

概述 企业设备管理扩展能力&#xff0c;是设备管理应用必备组件。当开发者为企业开发设备管理应用时&#xff0c;需继承EnterpriseAdminExtensionAbility&#xff0c;在EnterpriseAdminExtensionAbility实例中实现MDM业务逻辑&#xff0c;EnterpriseAdminExtensionAbility实现…

Xcode 16 上传AppStore遇到第三方库 bitcode 的问题

Xcode 16 上传AppStore遇到第三方库 bitcode 的问题 最近两天更新了Xcode 16&#xff0c;然后正好要发布新版本的App&#xff0c;打包Adhoc没问题&#xff0c;但是上传AppStoreConnect或者TestFlight就不行解决方案参考资料 最近两天更新了Xcode 16&#xff0c;然后正好要发布新…

【裸机装机系列】15.kali(ubuntu)-重装linux步骤

推荐阅读&#xff1a; 1.kali(ubuntu)-为什么弃用ubuntu&#xff0c;而选择基于debian的kali操作系统 如果你想重装linux系统&#xff0c;因为装机时采用了LVM分区的方式&#xff0c;那就可以按照下面步骤来操作&#xff1a; 保留 /home分区&#xff0c;“/swap”可以不动&am…

修改Opcenter EXFN 页面超时时间(Adjust UI Session Extend Token)

如果你想修改Opcenter EXFN中页面Session的超时时间&#xff0c;你可以按照如下步骤修改SessionAge 这个参数&#xff1a; 管理员运行CMD执行以下命令 umconf -getconfig -file C:\temp\config.json如果第2步有报错&#xff0c;则执行步骤4;如果没有报错则执行第5步如果第2步…

权限维持——Linux

前提 已经提权到管理员权限 一、创建账户 1、创建一个自定义密码的账户 已知&#xff0c;Linux中所有的用户的信息 存储在/etc/passwd这个文件中 。可以利用管理员权限修改这个文件&#xff0c; 添加一个账户 。 利用linux中的密码的编码算法 生成对应密码 &#xff08;不知…

2024年”3D Awards”优秀作品提名新鲜出炉

第九届渲染大赛落下帷幕&#xff0c; 有些小伙伴可能还没过瘾&#xff0c; 这不&#xff0c; 一年一度”3D Awards“优秀作品提名&#xff0c; 新鲜出炉&#xff01; 效果图提名&#xff08;排名不分先后&#xff09; 作品设计&#xff1a;Korolyov Ilya&#xff0c;Studio N…

【笔记】1.3 塑性变形

一、塑性变形的方式 DDWs&#xff08;Dislocation-Dipole Walls&#xff0c;位错偶极墙&#xff09;&#xff1a;指由两个位错构成的结构&#xff0c;它们以一种特定的方式排列在一起&#xff0c;形成一个稳定的结构单元。 DTs&#xff08;Dislocation Tangles&#xff0c;位错…

市面第一款 C++ 版本的U盘装机软件(即将上线)

市面大部分U盘装机软件&#xff0c;都是采用Au3脚本开发&#xff0c;而且有各种捆绑&#xff0c;闲来无聊&#xff0c;采用Qt C制作一款CU盘装机软件&#xff0c;从此告别Au3脚本&#xff0c;各种炫酷界面随便换&#xff0c;敬请期待 另外两个界面暂时不公布&#xff0c;防止Au…

CKKS同态加密通用函数近似方法和openFHE实现

摘要 同态加密可以直接在密文上进行运算&#xff0c;尤其是CKKS&#xff0c;可以直接在实数的密文上进行运算。服务器可以利用强大的计算能力&#xff0c;在不泄露用户隐私的情况下&#xff0c;为用户提供便捷的外包运算服务。然而&#xff0c;CKKS只能进行算术运算&#xff0…

【第2章 开始学习C++】进入C++

文章目录 导语C语言输入和输出main( )函数作为接口的函数头C预处理器和iostream文件头文件名名称空间使用 cout 进行 C 输出控制符 endl 导语 首先介绍一个显示消息的简单C程序。 源代码中包含一些供读者阅读的注释&#xff0c; 这些注释都以 // 打头&#xff0c; 编译器将忽…

patroni高可用测试

pkill postgres 主库日志 2024-09-25 16:42:30,579 INFO: no action. I am (postgres-1a86e6d5-0-0), the leader with the lock 2024-09-25 16:42:40,577 INFO: no action. I am (postgres-1a86e6d5-0-0), the leader with the lock 2024-09-25 16:42:50,578 INFO: no action…