C++设计模式|创建型 3.抽象工厂模式

在上一篇文章中介绍了工厂模式,每个具体工厂负责生产一个专门的产品,其代码扩展性很好,这篇文章将介绍抽象工厂模式。

1.为什么要使用抽象工厂模式?

既然已经有了“工厂模式”,那为什么还会有抽象工厂模式呢?

这就涉及到创建“多类”对象了,在工厂方法模式中,每个具体工厂只负责创建单一的产品。但是如果有多类产品呢,比如说“手机”,一个品牌的手机有高端机、中低端机之分,这些具体的产品在工厂模式中都需要建立一个单独的工厂类,但是它们都是相互关联的,都共同属于同一个品牌,这就可以使用到【抽象工厂模式】。

抽象工厂模式可以确保一系列相关的产品被一起创建,这些产品能够相互配合使用,再举个例子,有一些家具,比如沙发、茶几、椅子,都具有古典风格的和现代风格的,抽象工厂模式可以将生产现代风格的家具放在一个工厂类中,将生产古典风格的家具放在另一个工厂类中,这样每个工厂类就可以生产一系列的家具

2.抽象工厂模式的基本结构

抽象工厂模式包含多个抽象产品类,多个具体产品类,一个抽象工厂接口和多个具体工厂类,给个具体工厂杜泽创建一组相关的产品。

  • 抽象产品接口AbstractProduct: 定义产品的接口,可以定义多个抽象产品接口,比如说沙发、椅子、茶几都是抽象产品。所谓抽象产品接口,其实就是表示生产产品的一个纯虚函数,具体实现由下面的具体产品类实现。
  • 具体产品类ConcreteProduct: 实现抽象产品接口,产品的具体实现,古典风格和沙发和现代风格的沙发都是具体产品。
  • 抽象工厂接口AbstractFactory: 声明一组用于创建产品的方法,每个方法对应一类产品。该接口也是纯虚函数,具体实现有具体工厂类完成。
  • 具体工厂类ConcreteFactory 实现抽象工厂接口,负责创建一组具体产品的对象,在本例中,生产古典风格的工厂和生产现代风格的工厂都是具体实例。

 下面可以根据具体代码再理解上面的内容。

3.C++抽象工厂模式

【设计模式专题之抽象工厂模式】3. 家具工厂 (kamacoder.com)icon-default.png?t=N7T8https://kamacoder.com/problempage.php?pid=1077

题目描述:

小明家新开了两个工厂用来生产家具,一个生产现代风格的沙发和椅子,一个生产古典风格的沙发和椅子,现在工厂收到了一笔订单,请你帮他设计一个系统,描述订单需要生产家具的信息。

输入描述:

输入的第一行是一个整数 N(1 ≤ N ≤ 100),表示订单的数量。 

接下来的 N 行,每行输入一个字符串,字符串表示家具的类型。家具类型分为 "modern" 和 "classical" 两种。

输出描述:

对于每笔订单,输出字符串表示该订单需要生产家具的信息。 

modern订单会输出下面两行字符串 

modern chair 

modern sofa

classical订单会输出下面两行字符串 

classical chair 

classical sofa

输入示例: 

3
modern
classical
modern

输出示例:

modern chair
modern sofa
classical chair
classical sofa
modern chair
modern sofa

在上面的示例中,工厂收到了3笔订单,其中有2笔要求生产modern风格,1笔要求生产classical风格。根据输入的类型,每次订单生产的家具信息被输出到控制台上。 

代码实现: 

1.多个抽象产品类和多个具体产品类

根据题目,生产的产品有椅子和沙发两种,每种产品有现代和古典两种风格,那个椅子和沙发会各自对应一个抽象产品类,而现代椅子和古典椅子,现代沙发和古典沙发将是这两个抽象产品类的具体产品类。代码如下:

//抽象椅子类,里面包含生产接口produce()
class Chair{
public:
    //抽象产品生产接口
    virtual void produce() = 0;
};

//具体现代风格椅子类
class ModernChair : public Chair{
public:
    //多态实现具体抽象产品生产接口的具体化
    void produce() override{
        cout<<"modern chair"<<endl;
    }
};

//具体古典风格椅子类
class ClassicalChair : public Chair{
public:
//多态实现具体抽象产品生产接口的具体化
    void produce() override{
        cout<<"classical chair"<<endl;
    }
};


//抽象沙发类
class Sofa{
public:
    virtual void produce() = 0;
};

//具体现代沙发类
class ModernSofa:public Sofa{
public:
    void produce() override{
        cout<<"modern sofa"<<endl;
    }
};

//具体古典沙发类
class ClassicalSofa:public Sofa{
public:
    void produce() override{
        cout<<"classical sofa"<<endl;
    }
};

 2.一个抽象工厂类和多个具体工厂类

抽象工厂定义了生产产品的动作接口,具体工厂可以生产同风格的多种产品。

/下面是抽象工厂类,声明一组用于创建产品的方法,每个方法对应一种产品
class AbstractFurnitureFactory{
public:
    virtual Chair* createChair() = 0;
    virtual Sofa* createSofa() = 0;
};


//有了抽象工厂,需要设计具体工厂类,每个类负责生产同一风格的多种不同产品

//具体现代风格家具工厂类
class ModernFurnitureFactory:public AbstractFurnitureFactory{
public:
    //生产现代风格的椅子
    Chair * createChair() override{
        return new ModernChair();
    }
    
    //生产现代风格的沙发
    Sofa* createSofa() override{
        return new ModernSofa();
    }
    
};

//具体古典风格家具工厂类
class ClassicalFurnitureFactory:public AbstractFurnitureFactory{
public:
    //生产古典风格的椅子
    Chair * createChair() override{
        return new ClassicalChair();
    }
    
    //生产古典风格的沙发
    Sofa* createSofa() override{
        return new ClassicalSofa();
    }
    
};

整体代码如下:

#include<iostream>
#include<string>
using namespace std;

//生产的产品大类有椅子chair和沙发sofa两种
//根据抽象工厂模式的要求,要有抽象产品类及其对应的具体产品类
//所以下面先创建chair和sofa的抽象产品类

//抽象椅子类,里面包含生产接口produce()
class Chair{
public:
    virtual void produce() = 0;
};

//具体现代风格椅子类
class ModernChair : public Chair{
public:
    void produce() override{
        cout<<"modern chair"<<endl;
    }
};

//具体古典风格椅子类
class ClassicalChair : public Chair{
public:
    void produce() override{
        cout<<"classical chair"<<endl;
    }
};


//抽象沙发类
class Sofa{
public:
    virtual void produce() = 0;
};

//具体现代沙发类
class ModernSofa:public Sofa{
public:
    void produce() override{
        cout<<"modern sofa"<<endl;
    }
};

//具体古典沙发类
class ClassicalSofa:public Sofa{
public:
    void produce() override{
        cout<<"classical sofa"<<endl;
    }
};


//下面是抽象工厂类,声明一组用于创建产品的方法,每个方法对应一种产品
class AbstractFurnitureFactory{
public:
    virtual Chair* createChair() = 0;
    virtual Sofa* createSofa() = 0;
};


//有了抽象工厂,需要设计具体工厂类,每个类负责生产同一风格的多种不同产品

//具体现代风格家具工厂类
class ModernFurnitureFactory:public AbstractFurnitureFactory{
public:
    //生产现代风格的椅子
    Chair * createChair() override{
        return new ModernChair();
    }
    
    //生产现代风格的沙发
    Sofa* createSofa() override{
        return new ModernSofa();
    }
    
};

//具体古典风格家具工厂类
class ClassicalFurnitureFactory:public AbstractFurnitureFactory{
public:
    //生产古典风格的椅子
    Chair * createChair() override{
        return new ClassicalChair();
    }
    
    //生产古典风格的沙发
    Sofa* createSofa() override{
        return new ClassicalSofa();
    }
    
};


int main()
{
    //读取订单数量
    int N;
    cin>>N;
    
    //处理订单
    for(int i=0; i<N; ++i){
        string furnitureType; //准备读取家具类型
        cin>>furnitureType;
        
        //创建相应风格的具体家具工厂
        AbstractFurnitureFactory * factory = nullptr;
        if(furnitureType == "modern"){
            factory = new ModernFurnitureFactory();
        }
        else if(furnitureType == "classical"){
            factory = new ClassicalFurnitureFactory();    
        }
        
        //工厂去生产同风格的多个产品
        //生产该风格的椅子
        Chair * chair = factory->createChair();
        //生产该风格的沙发
        Sofa * sofa = factory->createSofa();
        
        //输出信息
        chair->produce();
        sofa->produce();
        
        //内存释放
        delete chair;
        delete sofa;
        delete factory;
        
    }
    return 0;
}

简单工厂、工厂模式、抽象工厂模式的区别

  • 简单工厂模式:一个工厂方法创建所有具体产品

  • 工厂方法模式:一个具体工厂方法创建一个具体产品

  • 抽象工厂模式:一个具体工厂方法可以创建一类具体产品

抽象工厂模式应用场景: 

抽象工厂模式能够保证一系列相关的产品一起使用,并且在不修改客户端代码的情况下,可以方便地替换整个产品系列。但是当需要增加新的产品类时,除了要增加新的具体产品类,还需要添加新的抽象工厂接口,修改所有的具体工厂类的生产函数(使其也能够同时生产该类型的新产品),扩展性相对较差。因此抽象工厂模式特别适用于一系列相关或相互依赖的产品被一起创建的情况,典型的应用场景是使用抽象工厂模式来创建与不同数据库的连接对象。

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

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

相关文章

基于docker的Jenkin的服务平台搭建

项目拓扑图 项目环境: jenkins-2.440 sonarqube-9.9.4 apache-maven-3.9.6 gitlab-ce-12.4.2 java17 docker20 harbor.v2.6.0 centos7.9 项目目的: 模拟企业构建一个流行的持续集成和持续部署环境,可以更轻松地创建和管理构建环境&#xff0c;实现自动化构建和部署应用程序的…

Tomcat命令行窗口、IDEA中Tomcat控制台 中文乱码问题解决方案

Tomcat出现中文乱码问题 打开Tomcat文件夹下的conf/logging.properties文件&#xff0c;将下图位置中的编码由UTF-8全部替换成GBK 然后重启Tomcat服务器&#xff0c;问题解决 Intellij IDEA启动Tomcat服务器控制台出现中文乱码 解决方案非常简单&#xff0c;按照下图设置控制…

智能边缘计算采集网关助您远程调试SINAMICS S200伺服-天拓四方

您还在为每次调试都要去现场而烦恼吗&#xff1f;智能边缘计算采集网关助您远程调试SINAMICS S200伺服&#xff0c;让您足不出户&#xff0c;就能“运筹帷幄之中&#xff0c;决胜千里之外”。 新品介绍 SINAMICS S200 PN是西门子推出的新一代伺服驱动系统&#xff0c;采用Mot…

kafka安装配置及使用

kafka安装配置及使用 kafka概述 Kafka 是一个分布式流处理平台和消息队列系统&#xff0c;最初由 LinkedIn 公司开发并开源。它设计用于处理大规模的实时数据流&#xff0c;并具有高可扩展性、高吞吐量和持久性等特性。以下是 Kafka 的一些主要特点和用途&#xff1a; 分布式架…

Vue3从入门到实战:深度掌握组件通信(上部曲)

props的概念&#xff1a; 当你使用Vue 3的组合式API时&#xff0c;props就是一种让你可以从父组件向子组件传递数据的方式。你可以想象成你在给子组件写一封信&#xff0c;把需要传递的信息放在信封里。 在Vue 3中&#xff0c;你可以在子组件的代码中定义props&#xff0c;就…

最新最全的Jmeter接口测试必会技能:jmeter对图片验证码的处理

jmeter对图片验证码的处理 在web端的登录接口经常会有图片验证码的输入&#xff0c;而且每次登录时图片验证码都是随机的&#xff1b;当通过jmeter做接口登录的时候要对图片验证码进行识别出图片中的字段&#xff0c;然后再登录接口中使用&#xff1b; 通过jmeter对图片验证码…

OpenHarmony南向开发案例【智慧中控面板(基于 Bearpi-Micro)】

1 开发环境搭建 【从0开始搭建开发环境】【快速搭建开发环境】 参考鸿蒙开发指导文档&#xff1a;gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md点击或复制转到。 【注意】&#xff1a;快速上手教程第六步出拉取代码时需要修改代码仓库地址 在MobaXterm中输入…

考研数学|《1800》《660》《880》如何选择和搭配?(附资料分享)

直接说结论&#xff1a;基础不好先做1800、强化之前660&#xff0c;强化可选880/1000题。 首先&#xff0c;传统习题册存在的一个问题是题量较大&#xff0c;但难度波动较大。《汤家凤1800》和《张宇1000》题量庞大&#xff0c;但有些题目难度不够平衡&#xff0c;有些过于简单…

【笔试训练】day4

不到5分钟写完&#xff0c;今天的题又又又难一点啦! 1.Fibonacci数列 思路&#xff1a; 直接模拟一遍斐波那契数列的递增过程&#xff0c;大于n就直接结束。因为后面只会越来越大&#xff0c;跟题目求的最小步数不符。在这个过程中用一个变量去维护这个当前的元素与目标n还差…

IntelliJ IDEA配置类注释模板和方法注释模板

配置类注释模板和方法注释模板 IDEA模板预定义变量类注释模方法注释模板方法参数优化 IDEA模板 在IDEA中&#xff0c;自带的注释模板可能不满足自身需求或者不满意&#xff0c;此时可以通过配置IDEA模板来解决。 预定义变量 内置模板是可编辑的&#xff0c;除了静态文本、代码和…

力扣hot100:136. 只出现一次的数字 及其衍生

文章目录 一、LeetCode&#xff1a;136. 只出现一次的数字 使用到的异或运算的特点&#xff1a; 两个相同的数异或&#xff0c;结果为0 一、LeetCode&#xff1a;136. 只出现一次的数字 LeetCode&#xff1a;136. 只出现一次的数字 这里数组nums的特点是&#xff0c;除了一…

近屿OJAC带你解读:什么是预训练(pre-training)?

预训练&#xff08;Pre-training&#xff09;是深度学习中一种常见的技术&#xff0c;特别是在自然语言处理&#xff08;NLP&#xff09;和计算机视觉等领域。预训练模型的目的是在特定任务之前&#xff0c;先在大量数据上训练一个模型&#xff0c;使其学习到通用的特征和知识。…

EelasticSearch安装及分词器安装

Docker安装 首先在你的linux系统的opt目录下创建一个es7文件夹&#xff0c;然后再在里面创建一个data文件夹&#xff08;data可省略在运行下面命令时它会自动创建&#xff09; docker run -d --name es7 -e ES_JAVA_POTS"-Xms256m -Xmx256m" -e "discovery.ty…

Ai2024安装包(亲测可用)

目录 一、软件简介 二、软件下载 一、软件简介 Adobe illustrator&#xff0c;常被称为“AI”&#xff0c;是一种应用于出版、多媒体和在线图像的工业标准矢量插画的软件。作为一款非常好的矢量图形处理工具&#xff0c;该软件主要应用于印刷出版、海报书籍排版、专业插画、多…

Vue3从入门到实战:深度掌握组件通信(下部曲)

5.组件通信方式5-$attrs $attrs的概念&#xff1a; 在Vue中&#xff0c;$attrs 是一个特殊的属性&#xff0c;用于访问父组件向子组件传递的非特定属性。它可以让子组件轻松地获取父组件传递的属性&#xff0c;而无需在子组件中显式声明这些属性。 想象一下你有一个父组件和…

Latent Guard、Tokenization in LLM、​3D Human Scan、FusionPortableV2

本文首发于公众号&#xff1a;机器感知 https://mp.weixin.qq.com/s/HlVV3VnqocBI4XBOT6RFHg A Multi-Level Framework for Accelerating Training Transformer Models The fast growing capabilities of large-scale deep learning models, such as Bert, GPT and ViT, are r…

微软开源 WizardLM-2,70B优于GPT4-0613,7B持平阿里最新的Qwen1.5-32B

当地时间4月15号&#xff0c;微软发布了新一代大语言模型 WizardLM-2&#xff0c;新家族包括三个尖端型号:WizardLM-2 8x22B, WizardLM-2 70B&#xff0c;和WizardLM-2 7B&#xff0c;作为下一代最先进的大型语言模型&#xff0c;它在复杂聊天、多语言、推理和代理方面的性能有…

算法打卡day37

今日任务&#xff1a; 1&#xff09;1049. 最后一块石头的重量 II 2&#xff09;494. 目标和 3&#xff09;474.一和零 4&#xff09;复习day12 1049. 最后一块石头的重量 II 题目链接&#xff1a;1049. 最后一块石头的重量 II - 力扣&#xff08;LeetCode&#xff09; 题目难…

B1100 校庆

输入样例&#xff1a; 5 372928196906118710 610481197806202213 440684198612150417 13072819571002001X 150702193604190912 6 530125197901260019 150702193604190912 220221196701020034 610481197806202213 440684198612150417 370205198709275042 输出样例&#xff1a;…

LINUX中使用cron定时任务被隐藏,咋回事?

一、问题现象 线上服务器运行过程中&#xff0c;进程有莫名进程被启动&#xff0c;怀疑是有定时任务自动启动&#xff0c;当你用常规方法去查看&#xff0c;比如使用crontab去查看定时器任务&#xff0c;提示no crontab for root 或者使用cat到/var/spool/cron目录下去查看定时…
最新文章