c++设计模式之一创建型模式

news2024/11/27 22:30:12

1、创建型模式(常见的设计模式)

Factory 模式(工厂模式,被实例化的子类)

在面向对象系统设计中经常可以遇到以下的两类问题:

下面是第一类问题和代码示例:我们经常会抽象出一些类的公共接口以形成抽象基类或者接口。这样我们可以通过声明一个指向基类的指针来指向实际的子类实现,达到了多态的目的。所以就不得不在要用到子类的地方写new 对象。这样实体类的使用者必须知道实际的子类名称,以及会使程序的扩展性和维护变得越来越困难。

#include <iostream>

// 抽象基类或接口
class Animal {
public:
    virtual void makeSound() = 0; // 纯虚函数
};

// 具体子类
class Dog : public Animal {
public:
    void makeSound() override {
        std::cout << "Woof!" << std::endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() override {
        std::cout << "Meow!" << std::endl;
    }
};

int main() {
    Animal* animal;

    // 通过指向基类的指针指向具体的子类实例
    animal = new Dog();
    animal->makeSound();

    animal = new Cat();
    animal->makeSound();

    return 0;
}

在上述示例中,我们定义了一个抽象基类 Animal,其中包含一个纯虚函数 makeSound()。然后我们派生出两个具体的子类 Dog 和 Cat,并分别实现了 makeSound() 方法。在 main() 函数中,我们使用指向基类的指针 animal,通过 new 实例化具体的子类,并调用其方法。这样可以实现多态性,但使用者需要知道具体的子类名称,不利于程序的扩展性和维护。 

还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。只能在父类中写方法调用,具体调用哪一个类的方法交给子类实现

#include <iostream>

// 抽象基类
class Animal {
public:
    virtual void makeSound() = 0; // 纯虚函数

    void performAction() {
        std::cout << "Performing action: ";
        makeSound();
    }
};

// 具体子类
class Dog : public Animal {
public:
    void makeSound() override {
        std::cout << "Woof!" << std::endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() override {
        std::cout << "Meow!" << std::endl;
    }
};

int main() {
    Animal* animal = nullptr;
    int choice;

    std::cout << "Enter 1 for Dog, 2 for Cat: ";
    std::cin >> choice;

    // 根据用户的选择实例化不同的子类
    if (choice == 1) {
        animal = new Dog();
    } else if (choice == 2) {
        animal = new Cat();
    } else {
        std::cout << "Invalid choice" << std::endl;
        return 0;
    }

    animal->performAction();

    delete animal;

    return 0;
}

在上述示例中,我们仍然有一个抽象基类 Animal,其中包含一个纯虚函数 makeSound()。不同之处在于,在 Animal 类中我们添加了一个 performAction() 方法,该方法调用了 makeSound() 方法。在 main() 函数中,根据用户的选择实例化不同的子类,并通过基类指针调用 performAction() 方法。这样,具体调用哪个子类的方法由子类自己实现,父类并不知道具体的子类实例化。

以上两个问题也就引出了 Factory 模式的两个最重要的功能:
1)定义创建对象的接口,封装了对象的创建。
2)使得具体化类的工作延迟到了子类中。

工厂模式代码示例

#include <iostream>
#include <string>

// 抽象产品类
class Product {
public:
    virtual void use() const = 0;
};

// 具体产品类 A
class ConcreteProductA : public Product {
public:
    void use() const override {
        std::cout << "Using ConcreteProductA" << std::endl;
    }
};

// 具体产品类 B
class ConcreteProductB : public Product {
public:
    void use() const override {
        std::cout << "Using ConcreteProductB" << std::endl;
    }
};

// 工厂类
class Factory {
public:
    virtual Product* createProduct() const = 0;

    Product* getProduct() const {
        Product* product = createProduct();
        // 可以在这里添加其他的初始化逻辑
        return product;
    }
};

// 具体工厂类 A
class ConcreteFactoryA : public Factory {
public:
    Product* createProduct() const override {
        return new ConcreteProductA();
    }
};

// 具体工厂类 B
class ConcreteFactoryB : public Factory {
public:
    Product* createProduct() const override {
        return new ConcreteProductB();
    }
};

int main() {
    Factory* factory = nullptr;
    Product* product = nullptr;
    std::string choice;

    std::cout << "Enter A for ConcreteProductA, B for ConcreteProductB: ";
    std::cin >> choice;

    // 根据用户的选择实例化不同的具体工厂类
    if (choice == "A") {
        factory = new ConcreteFactoryA();
    } else if (choice == "B") {
        factory = new ConcreteFactoryB();
    } else {
        std::cout << "Invalid choice" << std::endl;
        return 0;
    }

    // 使用工厂类创建产品对象
    product = factory->getProduct();
    product->use();

    delete factory;
    delete product;

    return 0;
}

AbstactFactory 模式 (产品对象家族)

假如我们要买水果,水果的产地来自中国、日本、美国,每个国家的水果种类都可以分为苹果、香蕉、梨子。作为开发者,我们就不得不创建苹果类(香蕉和梨子类似),然后每种苹果都继承自苹果类。每上架一个国家的苹果我们都要实现一次苹果类,这样就会有成千上万的苹果类需要被创建,AbstractFactory 模式就是用来解决这类问题的:要创建一组相关或者相互依赖的对象。

//抽象工厂模式
#include <iostream>
using namespace std;

//苹果的抽象
class AbstractApple {
public:
    virtual void showName() = 0;
};

//中国苹果
class ChinaApple :public AbstractApple {
public:
    virtual void showName() {
        cout << "中国苹果" << endl;
    }
};

//美国苹果
class USAApple :public AbstractApple {
public:
    virtual void showName() {
        cout << "美国苹果" << endl;
    }
};

//日本苹果
class JapanApple :public AbstractApple {
public:
    virtual void showName() {
        cout << "日本苹果" << endl;
    }
};

//香蕉的抽象
class AbstractBanana {
public:
    virtual void showName() = 0;
};

//中国香蕉
class ChinaBanana :public AbstractBanana {
public:
    virtual void showName() {
        cout << "中国香蕉" << endl;
    }
};

//美国香蕉
class USABanana :public AbstractBanana {
public:
    virtual void showName() {
        cout << "美国香蕉" << endl;
    }
};

//日本香蕉
class JapanBanana :public AbstractBanana {
public:
    virtual void showName() {
        cout << "日本香蕉" << endl;
    }
};

//鸭梨的抽象
class AbstractPear {
public:
    virtual void showName() = 0;
};

//中国鸭梨
class ChinaPear :public AbstractPear {
public:
    virtual void showName() {
        cout << "中国鸭梨" << endl;
    }
};

//美国鸭梨
class USAPear :public AbstractPear {
public:
    virtual void showName() {
        cout << "美国鸭梨" << endl;
    }
};

//日本鸭梨
class JapanPear :public AbstractPear {
public:
    virtual void showName() {
        cout << "日本鸭梨" << endl;
    }
};

//抽象工厂  针对产品族
class AbstractFactory {
public:
    virtual AbstractApple* CreateApple() = 0;
    virtual AbstractBanana* CreateBanana() = 0;
    virtual AbstractPear* CreatePear() = 0;
};

//中国工厂
class ChinaFactory :public AbstractFactory {
    virtual AbstractApple* CreateApple() {
        return new ChinaApple;
    }
    virtual AbstractBanana* CreateBanana() {
        return new ChinaBanana;
    }
    virtual AbstractPear* CreatePear() {
        return new ChinaPear;
    }
};

//美国工厂
class USAFactory :public AbstractFactory {
    virtual AbstractApple* CreateApple() {
        return new USAApple;
    }
    virtual AbstractBanana* CreateBanana() {
        return new USABanana;
    }
    virtual AbstractPear* CreatePear() {
        return new USAPear;
    }
};

//日本工厂
class JapanFactory :public AbstractFactory {
    virtual AbstractApple* CreateApple() {
        return new JapanApple;
    }
    virtual AbstractBanana* CreateBanana() {
        return new JapanBanana;
    }
    virtual AbstractPear* CreatePear() {
        return new JapanPear;
    }
};

void test01() {
    AbstractFactory* factory = NULL;
    AbstractApple* apple = NULL;
    AbstractBanana* Banana = NULL;
    AbstractPear* Pear = NULL;

    //中国工厂
    factory = new ChinaFactory;
    apple = factory->CreateApple();
    Banana = factory->CreateBanana();
    Pear = factory->CreatePear();

    apple->showName();
    Banana->showName();
    Pear->showName();

    delete Pear;
    delete apple;
    delete Banana;
    delete factory;
}

int main()
{
    test01();
}

Singleton 模式( 单例模式,针对一个类的唯一实例)
Singleton 模式是设计模式中最为简单、最为常见、最容易实现,也是最应该熟悉和掌握的模式。Singleton 模式就是一个类只创建一个唯一的对象,即一次创建多次使用。

实现单例模式的步骤:
1、构造函数私有化
2、增加静态私有的当前类的指针变量
3、提供静态对外接口,可以让用户获得单例对象

单例分为懒汉式和饿汉式

懒汉式:解决了饿汉式内存浪费问题,但是线程不安全的,可以通过互斥量mutex.lock()和mutex.unlock()来解决,懒汉用的比较多
饿汉式:还没有使用该单例对象,该单例对象就已经被加载到内存了,在对象过多时会造成内存浪费,饿汉模式会在程序启动时就创建单例对象,并且该对象会一直存在于内存中,即使在程序执行过程中没有被使用。这可能会导致内存浪费,特别是在单例对象比较大或者创建单例对象需要消耗大量资源的情况下。

这个是饿汉模式,返回的是一个静态变量,静态变量没运行就会产生数据

class Singleton {
private:
    static Singleton instance;

    Singleton() {}

public:
    static Singleton& getInstance() {
        return instance;
    }

    void doSomething() {
        std::cout << "Singleton instance is doing something." << std::endl;
    }
};

Singleton Singleton::instance;

int main() {
    Singleton& singleton = Singleton::getInstance();
    singleton.doSomething();

    return 0;
}

这个是懒汉模式,返回的是一个静态变量指针,程序调用getinstance才会产生数据

#include <iostream>
#include <mutex>

class Singleton {
private:
    //类外定义成员变量
    static Singleton* instance;
    static std::mutex mutex;
    //构造函数私有化
    Singleton() {}

public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            std::lock_guard<std::mutex> lock(mutex);
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }

    void doSomething() {
        std::cout << "Singleton instance is doing something." << std::endl;
    }
};

Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;

int main() {
    Singleton* singleton = Singleton::getInstance();
    singleton->doSomething();

    return 0;
}

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

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

相关文章

vue3项目使用Electron打包成exe的方法与打包报错解决

将vue3项目打包成exe文件方法 一、安装 1.安装electron npm install electron --save-devnpm install electron-builder --save-dev 2.在vue项目根目录新建文件index.js // index.js// Modules to control application life and create native browser window const { app…

SBTI认证的申请流程是什么?

SBTI&#xff08;科学基准目标倡议&#xff09;认证的申请流程通常包括以下几个关键步骤&#xff0c;以下是根据参考文章整理出的清晰流程&#xff1a; 咨询和准备阶段&#xff1a; 企业首先需要咨询SBTI认证机构&#xff0c;了解认证的标准和要求&#xff0c;并确定是否有资格…

森林火灾扑救特类车辆有哪些_鼎跃安全

森林消防是在森林火灾发生时&#xff0c;为了保护森林资源&#xff0c;防止火势蔓延&#xff0c;采取了一系列的应用措施&#xff0c;针对自然环境中的火灾消防工作。森林灭火主要包括预警、预防措施、火情监测、火势控制和灭火等&#xff0c;森林火灾发生的地形往往复杂崎岖&a…

转炉五万立煤气柜柜位计消除虚假回波的方法

转炉五万立煤气柜柜位计消除虚假回波的方法 一、五万立转炉煤气柜柜位计问题 五万立转炉煤气柜工艺简介:五万立转炉煤气柜是将净化除尘后的一炼钢工序副产转炉煤气回收至气柜中储存,储存的转炉煤气在经过电除尘器净化除尘,经转炉煤气加压站加压后分别输送至一炼钢工序,吉瑞…

Hi3861 OpenHarmony嵌入式应用入门--PWM 三色灯

这篇文章是讲解的pwm控制三色灯的部分&#xff0c;这部分也是后续全彩智能灯的基础。 硬件原理如下 IO管脚定义在hi-12f_v1.1.2-规格书-20211202.pdf文档中 GPIO API API名称 说明 unsigned int IoTGpioInit(unsigned int id); GPIO模块初始化 hi_u32 hi_io_set_func(hi_i…

【Web APIs】DOM 文档对象模型 ④ ( querySelector 函数 | querySelectorAll 函数 | NodeList 对象 )

文章目录 一、querySelector 函数1、querySelector 函数简介2、完整代码示例 二、querySelectorAll 函数1、querySelectorAll 函数简介2、完整代码示例 三、NodeList 对象1、NodeList 对象简介2、完整代码示例 本博客相关参考文档 : WebAPIs 参考文档 : https://developer.moz…

Vue 自定义ElementUI的Loading效果

import { loadingText, messageDuration } from "/settings";import { Loading } from "element-ui"; // loadingText、messageDuration 这两个参数我是调的公共配置文件,按自己需求来 const install (Vue, opts {}) > {/* 全局多彩Loading加载层 *…

办公技能——如何写好会议纪要,提升职业素养

一、什么是会议纪要 会议纪要是一种记载、反映会议情况和议定事项的纪实性公文&#xff0c;是贯彻落实会议精神、指导工作、解决问题、交流经验的重要工具。 会议纪要可以多向行文&#xff1a;向上级机关汇报会议情况&#xff0c;以便得到上级机关对工作的指导&#xff1b;向同…

算法导论 总结索引 | 第四部分 第十五章:数据结构的扩张

1、动态规划&#xff08;dynamic programming&#xff09;与分治方法相似&#xff0c;都是通过组合子问题的解 来求解原问题 分治方法 将问题划分为互不相交的子问题&#xff0c;递归地求解子问题&#xff0c;再将它们的解组合起来。求出原问题的解 与之相反&#xff0c;动态规…

2024广东省职业技能大赛云计算赛项实战——编排部署ERP管理系统

编排部署ERP管理系统 前言 编写docker-compose.yaml文件&#xff0c;要求使用镜像mysql、redis、nginx和erp完成ERP管理系统的编排部署。 编写docker-compose.yaml完成ERP管理系统的部署&#xff0c;要求定义mysql、redis、nginx和erp共四个Service&#xff0c;分别使用镜像e…

Linux工具(包含sudo提权与vim快捷配置)

目录 什么是软件包 查看软件包 如何安装软件 1.官方yum源下载 2.扩展yum源下载 如何卸载软件 补充知识如何将普通用户加入白名单 补充知识rzsz vim编辑器 1.命令模式&#xff08;进入默认为这个模式&#xff09;用户所有的输入都会被当成命令 2.插入模式 3.底行模…

排序算法Java_实现

1.引言 查找和排序算法是算法的入门知识&#xff0c;其经典思想可以用于比较常见。 1.1 内部排序和外部排序的区别 内部排序&#xff1a;待排序记录存放在计算机随机存储器中(内存)进行排序的过程。 外部排序&#xff1a;待排序记录的数量很大&#xff0c;以至于内存不能一…

MyBatisplus使用报错--Invalid bound statement

报错如下 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.lotus.mybatis.mapper.UserMapper.selectListat org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:235)at com.baomidou.mybatisplus.cor…

微软TTS最新模型,发布9种更真实的AI语音

很高兴与大家分享 Azure AI 语音翻译产品套件的两个重大更新&#xff1a; 视频翻译和增强的实时语音翻译 API。 视频翻译&#xff08;批量&#xff09; 今天&#xff0c;我们宣布推出视频翻译预览版&#xff0c;这是一项突破性的服务&#xff0c;旨在改变企业本地化视频内容…

onlyoffice报错:这份文件无法保存。请检查连接设置或联系您的管理员当你点击

文章目录 一、onlyoffice报错&#xff1a;这份文件无法保存。请检查连接设置或联系您的管理员当你点击二、解决方法总结 一、onlyoffice报错&#xff1a;这份文件无法保存。请检查连接设置或联系您的管理员当你点击 二、解决方法 禁用防火墙 sudo ufw disable总结 作者&…

MySQL 面试突击指南:核心知识点解析1

MySQL中有哪些存储引擎? InnoDB存储引擎 InnoDB是MySQL的默认事务型引擎,也是最重要、使用最广泛的存储引擎,设计用于处理大量短期事务。 MyISAM存储引擎 在MySQL 5.1及之前版本,MyISAM是默认的存储引擎。它提供了全文索引、压缩、空间函数(GIS)等特性,但不支持事务和…

Linux ls-al命令实现,tree命令实现,不带缓存的文件IO(open,read,write)

shell命令 ls -al 实现 #include <43func.h> void error_check(int ret, const char *msg) {if (ret -1) {perror(msg);exit(EXIT_FAILURE);} }char get_file_type(mode_t mode) {if (S_ISREG(mode)) return -;//检查给定的文件模式&#xff08;通常是从 stat 或 lst…

36.6K star!Immich - 一款开源高性能的自托管照片和视频备份方案

大家好&#xff0c;今天给大家分享的是一个高性能的自托管照片和视频备份方案。 Immich 是一个图片管理和分享平台&#xff0c;它允许用户高效地组织、存储和访问他们的照片和视频集合。这个项目特别设计来优化个人和家庭的多媒体内容管理体验&#xff0c;提供了诸如自动备份、…

贾英才主任受聘担任“两个中心”专家委员会委员

近日&#xff0c;第二届海峡两岸中西医结合肾脏病学术大会授牌仪式在北京隆重举行。 这一盛会吸引了众多医学领域的专家学者&#xff0c;共同探讨中西医结合治疗肾脏病的最新进展和未来发展方向。 在此次大会上&#xff0c;崇文门中医医院的贾英才主任凭借其在肾脏病领域的卓…

绝地求生PUBG联名补偿奖励来了 补偿奖励介绍详情解析

绝地求生》(PUBG) 作为一款战术竞技型射击类沙盒游戏&#xff0c;从上线以来就深受玩家小伙伴们的喜爱&#xff0c;即便是没有玩过的小伙伴&#xff0c;对“吃 鸡”二字想必也是很耳熟的&#xff0c;这正是《绝地求生》(PUBG) 的别称。 在北京时间6月12日&#xff0c;由于绝地求…