设计模式 之 工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)(C++)

文章目录

  • C++ 工厂模式
    • 引言
    • 一、简单工厂模式
      • 概念
      • 实现步骤
      • 示例代码
      • 优缺点
    • 二、工厂方法模式
      • 概念
      • 实现步骤
      • 示例代码
      • 优缺点
    • 三、抽象工厂模式
      • 概念
      • 实现步骤
      • 示例代码
      • 优缺点

C++ 工厂模式

引言

在 C++ 编程中,对象的创建是一个常见且基础的操作。然而,当项目规模逐渐增大,对象的创建逻辑变得复杂时,直接在代码中使用 new 关键字创建对象会带来诸多问题,比如代码的可维护性变差、难以扩展等。工厂模式应运而生,它为对象的创建提供了一种更加灵活、可扩展的解决方案。本文将详细介绍 C++ 中的工厂模式,包括简单工厂模式、工厂方法模式和抽象工厂模式,并通过具体的例子帮助大家理解。

一、简单工厂模式

概念

简单工厂模式是工厂模式的基础版本,它定义了一个工厂类,该类可以根据传入的参数决定创建并返回哪种产品类的实例。简单来说,就是把对象的创建逻辑封装在一个工厂类中。

实现步骤

  1. 定义产品基类:创建一个抽象的产品基类,所有具体产品类都要继承这个基类。
  2. 创建具体产品类:实现产品基类的接口,创建具体的产品类。
  3. 创建工厂类:在工厂类中定义一个创建产品的方法,根据传入的参数决定创建哪种具体产品。

示例代码

#include<iostream>
#include<memory>

// 定义水果抽象基类,包含纯虚函数 name
class Fruit{
    public:
        // 纯虚函数,用于输出水果名称,派生类需实现
        virtual void name()=0;
};

// 苹果类,继承自 Fruit 类
class Apple:public Fruit{
    public:
        // 重写基类的 name 函数,输出苹果名称
        void name() override{
            std::cout<<"Apple"<<std::endl;
        }
};

// 香蕉类,继承自 Fruit 类
class Banana:public Fruit{
    public:
        // 重写基类的 name 函数,输出香蕉名称
        void name() override{
            std::cout<<"Banana"<<std::endl;
        }
};

// 工厂类,用于创建不同类型的水果对象
class Factory{
    public:
        // 静态方法,根据传入的水果名称创建对应的水果对象
        static std::unique_ptr<Fruit> createFruit(std::string fruit_name){
            if(fruit_name=="apple"){
                // 创建苹果对象并返回其 unique_ptr
                return std::unique_ptr<Fruit>(new Apple());
            }
            else if(fruit_name=="banana"){
                // 创建香蕉对象并返回其 unique_ptr
                return std::unique_ptr<Fruit>(new Banana());
            }
            else{
                // 若名称不匹配,返回空指针
                return nullptr;
            }
        }
};

int main()
{
    // 使用工厂类创建苹果对象
    std::unique_ptr<Fruit> fruit = Factory::createFruit("apple");
    // 调用苹果对象的 name 函数输出名称
    fruit->name();  
    // 使用工厂类创建香蕉对象
    fruit = Factory::createFruit("banana");
    // 调用香蕉对象的 name 函数输出名称
    fruit->name();
    // 再次使用工厂类创建苹果对象
    fruit = Factory::createFruit("apple");

    return 0;
}

优缺点

  • 优点:实现简单,将对象的创建和使用分离,提高了代码的可维护性。
  • 缺点:工厂类职责过重,违反了开闭原则(对扩展开放,对修改关闭)。如果需要新增产品,就需要修改工厂类的代码。

二、工厂方法模式

概念

工厂方法模式是在简单工厂模式的基础上进行了改进,它将创建对象的具体逻辑延迟到子类中实现。定义一个创建对象的抽象方法,让子类决定实例化哪个具体产品类。

实现步骤

  1. 定义产品基类:同简单工厂模式。
  2. 创建具体产品类:同简单工厂模式。
  3. 定义抽象工厂类:定义一个抽象的工厂类,其中包含一个抽象的创建产品的方法。
  4. 创建具体工厂类:继承抽象工厂类,实现创建产品的方法,决定创建哪种具体产品。

示例代码

#include<iostream>
#include<memory>

// 定义抽象基类 Fruit,包含纯虚函数 name
// 任何继承自该类的具体水果类都必须实现 name 函数
class Fruit {
public:
    // 纯虚函数,用于输出水果名称
    virtual void name() = 0;
};

// 定义 Apple 类,继承自 Fruit 类
class Apple : public Fruit {
public:
    // 重写基类的纯虚函数 name,输出苹果名称
    void name() override {
        std::cout << "Apple" << std::endl;
    }
};

// 定义 Banana 类,继承自 Fruit 类
class Banana : public Fruit {
public:
    // 重写基类的纯虚函数 name,输出香蕉名称
    void name() override {
        std::cout << "Banana" << std::endl;
    }
};

// 定义抽象工厂类 Factory,包含纯虚函数 create
// 具体的工厂类需要实现该函数来创建水果对象
class Factory {
public:
    // 纯虚函数,用于创建水果对象
    virtual std::shared_ptr<Fruit> create() = 0;
};

// 定义 AppleFactory 类,继承自 Factory 类
class AppleFactory : public Factory {
public:
    // 重写基类的纯虚函数 create,创建苹果对象
    std::shared_ptr<Fruit> create() override {
        return std::make_shared<Apple>();
    }
};

// 定义 BananaFactory 类,继承自 Factory 类
class BananaFactory : public Factory {
public:
    // 重写基类的纯虚函数 create,创建香蕉对象
    std::shared_ptr<Fruit> create() override {
        return std::make_shared<Banana>();
    }
};

int main() {
    // 创建一个指向 AppleFactory 的智能指针
    std::shared_ptr<Factory> fruit_factory(new AppleFactory());
    // 调用工厂的 create 方法创建苹果对象
    std::shared_ptr<Fruit> fruit = fruit_factory->create();
    // 调用水果对象的 name 方法输出名称
    fruit->name();

    // 重置工厂指针,指向 BananaFactory
    fruit_factory.reset(new BananaFactory());
    // 调用新工厂的 create 方法创建香蕉对象
    fruit = fruit_factory->create();
    // 调用水果对象的 name 方法输出名称
    fruit->name();

    return 0;
}

优缺点

  • 优点:符合开闭原则,当需要新增产品时,只需要新增具体产品类和对应的具体工厂类,不需要修改现有代码。
  • 缺点:类的数量会增多,增加了系统的复杂度。

三、抽象工厂模式

概念

抽象工厂模式:工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问题。但由于工厂方法模式中的每个工厂只生产一类产品,可能会导致系统中存在大量的工厂类,势必会增加系统的开销。此时,我们可以考虑将一些相关的产品组成一个产品族(位于不同产品等级结构中功能相关联的产品组成的家族),由同一个工厂来统一生产,这就是抽象工厂模式的基本思想。

实现步骤

  1. 定义产品族的抽象基类:为每个产品族定义一个抽象基类。
  2. 创建具体产品类:实现每个产品族的具体产品类。
  3. 定义抽象工厂类:定义一个抽象的工厂类,其中包含多个创建不同产品的抽象方法。
  4. 创建具体工厂类:继承抽象工厂类,实现创建不同产品的方法,决定创建哪些具体产品。

示例代码

#include<iostream>
#include<memory>

// 水果抽象基类,定义了输出水果名称的纯虚函数
class Fruit {
public:
    virtual void name() = 0;
};

// 苹果类,继承自 Fruit 类,实现了输出苹果名称的方法
class Apple : public Fruit {
public:
    void name() override {
        std::cout << "Apple" << std::endl;
    }
};

// 香蕉类,继承自 Fruit 类,实现了输出香蕉名称的方法
class Banana : public Fruit {
public:
    void name() override {
        std::cout << "Banana" << std::endl;
    }
};

// 动物抽象基类,定义了输出动物名称的纯虚函数
class Animal {
public:
    virtual void name() = 0;
};

// 羊类,继承自 Animal 类,实现输出名称方法
class Lamb : public Animal {
public:
    void name() override {
        std::cout << "Lamb" << std::endl;
    }
};

// 狗类,继承自 Animal 类,实现了输出狗名称的方法
class Dog : public Animal {
public:
    void name() override {
        std::cout << "Dog" << std::endl;
    }
};

// 抽象工厂类,定义了获取水果和动物对象的纯虚函数
class Factory {
public:
    virtual std::shared_ptr<Fruit> getFruit(const std::string& name) = 0;
    virtual std::shared_ptr<Animal> getAnimal(const std::string& name) = 0;
};

// 水果工厂类,继承自 Factory 类,实现了获取水果对象的方法,获取动物对象返回空指针
class FruitFactory : public Factory {
public:
    virtual std::shared_ptr<Fruit> getFruit(const std::string& name);
    virtual std::shared_ptr<Animal> getAnimal(const std::string& name);
};

// 动物工厂类,继承自 Factory 类,实现了获取动物对象的方法,获取水果对象返回空指针
class AnimalFactory : public Factory {
public:
    virtual std::shared_ptr<Fruit> getFruit(const std::string& name);
    virtual std::shared_ptr<Animal> getAnimal(const std::string& name);
};

// 工厂管理类,提供静态方法根据名称创建对应的工厂对象
class FactoryManager {
public:
    static std::shared_ptr<Factory> creaete(const std::string& name);
};

int main() {
    // 通过工厂管理类创建水果工厂对象
    std::shared_ptr<Factory> fruit_factory = FactoryManager::creaete("fruit");
    // 从水果工厂获取苹果对象并输出名称
    std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("apple");
    fruit->name();
    // 从水果工厂获取香蕉对象并输出名称
    fruit = fruit_factory->getFruit("banana");
    fruit->name();

    return 0;
}

优缺点

  • 优点:将一系列相关的产品对象的创建封装在一起,保证了产品之间的一致性,同时也符合开闭原则。
  • 缺点:实现复杂,当产品族需要增加新的产品时,需要修改抽象工厂类和所有具体工厂类的代码。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入了解 DevOps 基础架构:可追溯性的关键作用

在当今竞争激烈的软件环境中&#xff0c;快速交付强大的应用程序至关重要。尽管如此&#xff0c;在不影响质量的情况下保持速度可能是一项艰巨的任务&#xff0c;这就是 DevOps 中的可追溯性发挥作用的地方。通过提供软件开发生命周期 &#xff08;SDLC&#xff09; 的透明视图…

由浅入深学习大语言模型RLHF(PPO强化学习- v1浅浅的)

最近&#xff0c;随着DeepSeek的爆火&#xff0c;GRPO也走进了视野中。为了更好的学习GRPO&#xff0c;需要对PPO的强化学习有一个深入的理解&#xff0c;那么写一篇文章加深理解吧。纵观网上的文章&#xff0c;要么说PPO原理&#xff0c;各种复杂的公式看了就晕&#xff0c;要…

【Java八股文】08-计算机网络面试篇

【Java八股文】08-计算机网络面试篇 计算机网络面试篇网络模型网络OSI模型和TCP/IP模型分别介绍一下键入网址到网页显示&#xff0c;期间发生了什么&#xff1f; 应用层- HTTP应用层有哪些协议&#xff1f;HTTP是什么及HTTP报文有哪些部分&#xff1f;HTTP是怎么传输数据的HTTP…

【Linux】Linux 文件系统——有关 inode 不足的案例

ℹ️大家好&#xff0c;我是练小杰&#xff0c;今天周二了&#xff0c;明天星期三&#xff0c;还有三天就是星期五了&#xff0c;坚持住啊各位&#xff01;&#xff01;&#xff01;&#x1f606; 本文是对之前Linux文件权限中的inode号进行实例讨论&#xff0c;看到博客有错误…

SpringBoot整合Redis和Redision锁

参考文章 1.Redis 1.导入依赖 <!--Redis依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.c…

亲测可用,IDEA中使用满血版DeepSeek R1!支持深度思考!免费!免配置!

作者&#xff1a;程序员 Hollis 之前介绍过在IDEA中使用DeepSeek的方案&#xff0c;但是很多人表示还是用的不够爽&#xff0c;比如用CodeChat的方案&#xff0c;只支持V3版本&#xff0c;不支持带推理的R1。想要配置R1的话有特别的麻烦。 那么&#xff0c;今天&#xff0c;给…

一周学会Flask3 Python Web开发-Debug模式开启

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 默认情况&#xff0c;项目开发是普通模式&#xff0c;也就是你修改了代码&#xff0c;必须重启项目&#xff0c;新代码才生效&…

某手sig3-ios算法 Chomper黑盒调用

Chomper-iOS界的Unidbg 最近在学习中发现一个Chomper框架&#xff0c;Chomper 是一个模拟执行iOS可执行文件的框架&#xff0c;类似于安卓端大名鼎鼎的Unidbg。 这篇文章使用Chomper模拟执行某手的sig3算法&#xff0c;初步熟悉该框架。这里只熟悉模拟执行步骤以及一些常见的…

PyTorch 深度学习框架中 torch.cuda.empty_cache() 的妙用与注意事项

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 在使用 PyTorch 进行深度学习模型训练与调优过程中&#xff0c;torch.cuda.empty_cache() 方法作为一种高效工具被广泛采用&#xff1b;但其正确应用要求充分理解该方法的功能及最佳实践。下文将对该方…

巧用GitHub的CICD功能免费打包部署前端项目

近年来&#xff0c;随着前端技术的发展&#xff0c;前端项目的构建和打包过程变得越来越复杂&#xff0c;占用的资源也越来越多。我有一台云服务器&#xff0c;原本打算使用Docker进行部署&#xff0c;以简化操作流程。然而&#xff0c;只要执行sudo docker-compose -f deploy/…

配置Api自动生成

我的飞书:https://rvg7rs2jk1g.feishu.cn/docx/TVlJdMgYLoDJrsxAwMgcCE14nxt 使用Springfox Swagger生成API&#xff0c;并导入Postman&#xff0c;完成API单元测试 Swagger: 是一套API定义的规范&#xff0c;按照这套规范的要求去定义接口及接口相关信息&#xff0c;再通过可…

【JMeter使用-2】JMeter中Java Request采样器的使用指南

Apache JMeter 是一款功能强大的性能测试工具&#xff0c;支持多种协议和测试场景。除了内置的采样器&#xff08;如HTTP请求、FTP请求等&#xff09;&#xff0c;JMeter还允许通过 Java Request采样器 调用自定义的Java代码&#xff0c;从而实现更复杂的测试逻辑。本文将详细介…

将Google文档导入WordPress:简单实用的几种方法

Google文档是内容创作者非常实用的写作工具。它支持在线编辑、多人协作&#xff0c;并能够自动保存内容。但当我们想把Google文档中的内容导入WordPress网站时&#xff0c;可能会遇到一些小麻烦&#xff0c;比如格式错乱、图片丢失等问题。本文将为大家介绍几种简单实用的方法&…

Android开发-深入解析Android中的AIDL及其应用场景

深入解析 Android 中的 AIDL 及其应用场景 1. 前言2. AIDL 的核心概念3. AIDL 的实现步骤3.1. 定义 AIDL 接口文件3.2. 实现服务端&#xff08;Service&#xff09;3.3. 客户端绑定与调用 4. AIDL 的典型应用场景4.1. 多进程应用4.2. 与系统服务交互4.3. 高性能 IPC4.4. 跨应用…

PWM(脉宽调制)技术详解:从基础到应用实践示例

PWM&#xff08;脉宽调制&#xff09;技术详解&#xff1a;从基础到应用实践示例 目录 PWM&#xff08;脉宽调制&#xff09;技术详解&#xff1a;从基础到应用实践示例学前思考&#xff1a;一、PWM概述二、PWM的基本原理三、PWM的应用场景四、PWM的硬件配置与使用五、PWM的编程…

谷粒商城—分布式高级②.md

认证服务 1. 环境搭建 创建gulimall-auth-server模块,导依赖,引入login.html和reg.html,并把静态资源放到nginx的static目录下 2. 注册功能 (1) 验证码倒计时 //点击发送验证码按钮触发下面函数 $("#sendCode").click(function () {//如果有disabled,说明最近…

Nginx(详解以及如何使用)

目录 1. 什么是Nginx&#xff1f; 2. 为什么使用nginx? 3. 安装nginx 3.1?安装nginx的依赖插件 3.2 下载nginx ?3.3?创建一个目录作为nginx的安装路径 ?3.4?解压 ?3.5?进入解压后的目录 3.6?指定nginx的安装路径 ?3.7?编译和安装nginx 3.8 启动nginx ?…

STM32 HAL库标准库+ESP8266+机智云

前言 最近在项目中需要云平台对接&#xff0c;前面使用的是阿里云物理平台&#xff0c;具体开发可以看看我的这个文章&#xff1a;手把手教会使用阿里云平台&#xff0c;不过好像没有可以在手机很方便打开连接的&#xff0c;所以我在网上找到一些资料&#xff0c;发现机智云是…

【前端框架】Vue3 面试题深度解析

本文详细讲解了VUE3相关的面试题&#xff0c;从基础到进阶到高级&#xff0c;分别都有涉及&#xff0c;希望对你有所帮助&#xff01; 基础题目 1. 简述 Vue3 与 Vue2 相比有哪些主要变化&#xff1f; 答案&#xff1a; 响应式系统&#xff1a;Vue2 使用 Object.definePrope…

DarkLabel 2.4使用指南:高效标注视频数据目标检测标签

工具概述 DarkLabel 2.4 是一款强大的多功能标注工具&#xff0c;专为计算机视觉开发者设计&#xff0c;旨在提升标注工作的效率和精确度。其智能标注引擎支持两项核心功能&#xff1a;线性插值标注与多目标跟踪&#xff0c;极大地优化了视频标注过程。 &#xff08;1&#x…