《C++设计模式》工厂模式

embedded/2024/12/25 13:58:05/

文章目录

  • 1、简介
  • 2、工厂模式的种类
    • 2.1 简单工厂模式(Simple Factory Pattern):
    • 2.2 工厂方法模式(Factory Method Pattern):
    • 2.3 抽象工厂模式(Abstract Factory Pattern):
  • 3、工厂模式的具体介绍
    • 3.1 简单工厂模式
      • 3.1.1 代码示例
      • 3.1.2 组成部分
      • 3.1.3 优缺点
      • 3.1.4 应用场景
    • 3.2 工厂方法模式
      • 3.2.1 代码示例
      • 3.2.2 组成部分
      • 3.2.3优缺点
      • 3.2.4应用场景
    • 3.3 抽象工厂模式
      • 3.3.1 代码示例
      • 3.3.2 组成部分
      • 3.3.3优缺点
      • 3.3.4 应用场景
  • 4、面试常问问题
    • 4.1、工厂模式基本概念
    • 4.2、工厂模式的应用场景
    • 4.3、工厂模式的实现方式
    • 4.4、工厂模式与其他设计模式的对比
    • 4.5、工厂模式的优缺点
  • 5、总结
  • 6、参考文章

1、简介

工厂模式(Factory Pattern)是创建型设计模式的一种,它提供了一种创建对象的最佳方式。在工厂模式中,一个工厂类负责创建具有共同接口或基类的对象,但无需明确指定将要创建的对象的具体类。这种模式通过将对象的实例化推迟到子类来实现,从而使得代码更加灵活和可扩展。

2、工厂模式的种类

2.1 简单工厂模式(Simple Factory Pattern):

也称为静态工厂方法模式,它通过一个工厂类来创建对象,但这个工厂类通常是一个静态方法。
客户端直接调用静态方法来获取所需的对象,而无需知道具体类的实现。

2.2 工厂方法模式(Factory Method Pattern):

定义一个用于创建对象的接口,但让子类决定实例化哪一个类。
工厂方法使得一个类的实例化延迟到其子类。
在这个模式中,父类提供一个创建对象的接口(通常是抽象方法),而子类则实现这个接口来创建具体的对象。

2.3 抽象工厂模式(Abstract Factory Pattern):

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
抽象工厂模式通常包含多个工厂方法,每个方法对应一个产品类。
这个模式使得客户端能够使用抽象接口来创建一系列相关的对象,而无需指定它们的具体实现类。

3、工厂模式的具体介绍

3.1 简单工厂模式

3.1.1 代码示例

#include <iostream>
#include <memory> // 包含智能指针的头文件using namespace std;// 鞋子抽象类
class Shoes
{
public:virtual ~Shoes() {}virtual void Show() = 0;
};// 耐克鞋子
class NiKeShoes : public Shoes
{
public:void Show() override{std::cout << "Nike:Just do it" << std::endl;}
};// 阿迪达斯鞋子
class AdidasShoes : public Shoes
{
public:void Show() override{std::cout << "Adidas: Impossible is nothing" << std::endl;}
};enum SHOES_TYPE
{NIKE,ADIDAS
};// 总鞋厂
class ShoesFactory
{
public:// 根据鞋子类型创建对应的鞋子对象,并返回智能指针std::unique_ptr<Shoes> CreateShoes(SHOES_TYPE type){switch (type){case NIKE:return std::make_unique<NiKeShoes>();case ADIDAS:return std::make_unique<AdidasShoes>();default:return nullptr; // 注意这里返回nullptr而不是NULL,这是C++11及以后版本的推荐做法}}
};int main()
{ShoesFactory shoesFactory;// 从鞋工厂对象创建耐克鞋对象auto pNikeShoes = shoesFactory.CreateShoes(NIKE);if (pNikeShoes){// 耐克球鞋广告喊起pNikeShoes->Show();}// 从鞋工厂对象创建阿迪达斯鞋对象auto pAdidasShoes = shoesFactory.CreateShoes(ADIDAS);if (pAdidasShoes){// 阿里达斯球鞋广告喊起pAdidasShoes->Show();}return 0;
}

3.1.2 组成部分

工厂类(ShoesFactory):工厂模式的核心类,会定义一个用于创建指定的具体实例对象的接口。
抽象产品类(Shoes):是具体产品类的继承的父类或实现的接口。
具体产品类(NiKeShoes\AdidasShoes\LiNingShoes):工厂类所创建的对象就是此具体产品实例。

3.1.3 优缺点

优点:
(1)实现了对象创建和使用的分离:客户端无需了解对象的具体创建过程,只需要关心如何使用对象。
(2)代码结构简单:容易理解和实现。
缺点:
(1)不符合开闭原则:当需要增加新的产品对象时,需要修改工厂类的代码,导致系统的可扩展性差。
(2)大量使用if-else语句:在简单工厂模式中,通常需要根据输入参数的不同来创建不同的对象,这会导致工厂类中出现大量的if-else语句,使代码变得复杂且难以维护。

3.1.4 应用场景

(1)对象创建过程简单且数量较少的场景:
当系统中需要创建的对象种类较少,且创建过程相对简单时,可以使用简单工厂模式。通过工厂类提供的方法,客户端可以轻松地获取所需的对象实例,而无需关心对象的创建细节。
(2)客户端不需要知道对象创建过程的场景:
在某些情况下,客户端只需要使用对象,而不需要了解对象的创建过程。此时,可以使用简单工厂模式将对象的创建逻辑封装在工厂类中,使客户端代码更加简洁和清晰。
(3)需要对对象创建过程进行集中管理的场景:
如果系统中需要对对象的创建过程进行集中管理和控制,例如需要对创建过程进行优化或调整时,可以使用简单工厂模式。通过修改工厂类的代码,可以轻松地实现对对象创建过程的调整和优化,而无需修改客户端代码。

3.2 工厂方法模式

3.2.1 代码示例

#include <iostream>
#include <memory> // 包含智能指针的头文件using namespace std;// 鞋子抽象类
class Shoes
{
public:virtual ~Shoes() {}virtual void Show() = 0;
};// 耐克鞋子
class NiKeShoes : public Shoes
{
public:void Show() override{std::cout << "Niki:Just do it" << std::endl;}
};// 阿迪达斯鞋子
class AdidasShoes : public Shoes
{
public:void Show() override{std::cout << "Adidas:Impossible is nothing" << std::endl;}
};// 总鞋厂(抽象工厂)
class ShoesFactory
{
public:virtual std::unique_ptr<Shoes> CreateShoes() = 0;virtual ~ShoesFactory() = default; // 使用默认析构函数
};// 耐克生产者/生产链
class NiKeProducer : public ShoesFactory
{
public:std::unique_ptr<Shoes> CreateShoes() override{return std::make_unique<NiKeShoes>();}
};// 阿迪达斯生产者/生产链
class AdidasProducer : public ShoesFactory
{
public:std::unique_ptr<Shoes> CreateShoes() override{return std::make_unique<AdidasShoes>();}
};int main()
{// ================ 生产耐克流程 ==================== //// 鞋厂开设耐克生产线(使用智能指针管理)std::unique_ptr<ShoesFactory> niKeProducer = std::make_unique<NiKeProducer>();// 耐克生产线产出球鞋(智能指针自动管理内存)auto nikeShoes = niKeProducer->CreateShoes();// 耐克球鞋广告喊起nikeShoes->Show();// 无需手动释放nikeShoes和niKeProducer,它们会在作用域结束时自动释放// ================ 生产阿迪达斯流程 ==================== //// 鞋厂开设阿迪达斯生产线(使用智能指针管理)std::unique_ptr<ShoesFactory> adidasProducer = std::make_unique<AdidasProducer>();// 阿迪达斯生产线产出球鞋(智能指针自动管理内存)auto adidasShoes = adidasProducer->CreateShoes();// 阿迪达斯球鞋广告喊起adidasShoes->Show();// 同样,无需手动释放adidasShoes和adidasProducerreturn 0;
}

3.2.2 组成部分

抽象工厂类厂(ShoesFactory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
具体工厂类(NiKeProducer\AdidasProducer\LiNingProducer):继承于抽象工厂,实现创建对应具体产品对象的方式。
抽象产品类(Shoes):它是具体产品继承的父类(基类)。
具体产品类(NiKeShoes\AdidasShoes\LiNingShoes):具体工厂所创建的对象,就是此类

3.2.3优缺点

优点:
(1)符合开闭原则:当需要增加新的产品对象时,只需要增加一个具体的工厂子类,无需修改原有代码,具有较好的可扩展性。
(2)降低耦合度:通过工厂方法模式,将对象的创建和使用分离,降低了客户端代码与具体产品类之间的耦合度。
缺点:
(1)工厂子类过多:当产品种类非常多时,会产生大量的工厂子类,导致代码结构复杂,增加系统的维护成本。
(2)增加了系统的复杂性:虽然工厂方法模式可以很好地解决简单工厂模式中的扩展性问题,但同时也增加了系统的复杂性,因为需要引入多个工厂子类来创建不同的产品对象。

3.2.4应用场景

(1)创建对象的任务由多个具体子工厂完成的场景:
当系统中存在多个具体子工厂,每个子工厂负责创建不同类型的对象时,可以使用工厂方法模式。通过定义抽象工厂接口和具体工厂类,可以灵活地选择所需的工厂来创建对象。
(2)客户端只需要知道产品接口而不需要知道具体产品实现的场景:
在某些情况下,客户端只需要知道产品的接口,而不需要知道具体的产品实现。此时,可以使用工厂方法模式将产品的创建逻辑封装在工厂类中,使客户端代码更加通用和可维护。
(3)需要扩展新产品种类且不希望修改客户端代码的场景:
如果系统中需要扩展新的产品种类,且不希望修改客户端代码,可以使用工厂方法模式。通过增加新的具体工厂类来实现新产品的创建,而无需修改原有的客户端代码。

3.3 抽象工厂模式

3.3.1 代码示例

#include <iostream>
#include <memory> // 包含智能指针的头文件using namespace std;// 基类 衣服
class Clothe
{
public:virtual void Show() = 0;virtual ~Clothe() {}
};// 基类 鞋子
class Shoes
{
public:virtual void Show() = 0;virtual ~Shoes() {}
};// 耐克衣服
class NiKeClothe : public Clothe
{
public:void Show() override{cout << "我是耐克衣服,come on!" << endl;}
};// 耐克鞋子
class NiKeShoes : public Shoes
{
public:void Show() override{cout << "我是耐克球鞋,come on!" << endl;}
};// 总厂
class Factory
{
public:virtual std::unique_ptr<Shoes> CreateShoes() = 0;virtual std::unique_ptr<Clothe> CreateClothe() = 0;virtual ~Factory() {}
};// 耐克生产者/生产链
class NiKeProducer : public Factory
{
public:std::unique_ptr<Shoes> CreateShoes() override{return std::make_unique<NiKeShoes>();}std::unique_ptr<Clothe> CreateClothe() override{return std::make_unique<NiKeClothe>();}
};int main()
{// ================ 生产耐克流程 ==================== //// 鞋厂开设耐克生产线std::unique_ptr<Factory> niKeProducer = std::make_unique<NiKeProducer>();// 耐克生产线产出球鞋auto nikeShoes = niKeProducer->CreateShoes();// 耐克生产线产出衣服auto nikeClothe = niKeProducer->CreateClothe();// 耐克球鞋广告喊起nikeShoes->Show();// 耐克衣服广告喊起nikeClothe->Show();// 不需要手动释放资源,std::unique_ptr会自动管理return 0;
}

3.3.2 组成部分

抽象工厂类厂(ShoesFactory):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
具体工厂类(NiKeProducer):继承于抽象工厂,实现创建对应具体产品对象的方式。
抽象产品类(Shoes\Clothe):它是具体产品继承的父类(基类)。
具体产品类(NiKeShoes\NiKeClothe):具体工厂所创建的对象,就是此类。

3.3.3优缺点

优点:
(1)提供了更加灵活的代码结构:通过抽象工厂模式,可以创建一系列相关的产品对象,而不仅仅是单一的产品对象。这使得代码结构更加灵活,可以适应更复杂的业务需求。
(2)降低了客户端代码的修改成本:当需要增加新的产品对象系列时,只需要增加一个具体的工厂子类,无需修改原有代码,降低了客户端代码的修改成本。
(3)增强了系统的可扩展性:抽象工厂模式符合开闭原则,可以很好地应对未来可能出现的新需求。
缺点:
(1)实现复杂:抽象工厂模式的实现相对复杂,需要设计多个抽象类和具体类,增加了系统的复杂性。
(2)不适合简单的应用场景:对于简单的应用场景,使用抽象工厂模式可能会增加不必要的复杂性,导致代码可读性下降。
(3)对开闭原则的支持有局限性:虽然抽象工厂模式符合开闭原则,但当需要增加新的产品对象种类时,仍然需要修改抽象工厂和所有具体工厂的代码,这在一定程度上限制了其灵活性。

3.3.4 应用场景

(1)系统需要独立于具体产品创建、组合和表示的场景:
当系统需要独立于具体产品的创建、组合和表示时,可以使用抽象工厂模式。通过定义抽象工厂接口和具体工厂类,可以将产品的创建过程与系统的其他部分分离,从而实现系统的独立性和可扩展性。
(2)系统需要配置多个产品系列之一的场景:
如果系统中存在多个产品系列,且需要根据不同的需求选择其中一个产品系列进行配置时,可以使用抽象工厂模式。通过定义抽象工厂接口和具体工厂类,可以灵活地选择所需的产品系列来配置系统。
(3)需要强调一系列相关产品对象的设计以便进行联合使用的场景:
当系统中存在一系列相关的产品对象,并且这些对象需要联合使用时,可以使用抽象工厂模式。通过定义抽象工厂接口和具体工厂类,可以确保这些产品对象在设计和实现上保持一致性和协调性,从而方便它们的联合使用。
(4)提供一个产品类库而只想显示它们的接口而不是实现的场景:
如果系统提供了一个产品类库,并且只想向外部展示产品的接口而不是具体的实现细节时,可以使用抽象工厂模式。通过定义抽象工厂接口和具体工厂类,可以将产品的具体实现隐藏起来,只向外部提供产品的接口供其使用。

4、面试常问问题

4.1、工厂模式基本概念

(1)什么是工厂模式?
工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。在工厂模式中,一个工厂类负责创建具有共同接口或基类的对象,而无需指定它们的具体类。
(2)工厂模式有几种类型?
工厂模式通常包括简单工厂模式、工厂方法模式和抽象工厂模式三种类型。

4.2、工厂模式的应用场景

(1)简单工厂模式的应用场景是什么?
简单工厂模式适用于对象创建过程简单且数量较少的场景,或者客户端不需要知道对象创建过程的场景。
(2)工厂方法模式的应用场景是什么?
工厂方法模式适用于创建对象的任务由多个具体子工厂完成的场景,或者客户端只需要知道产品接口而不需要知道具体产品实现的场景。
(3)抽象工厂模式的应用场景是什么?
抽象工厂模式适用于系统需要独立于具体产品创建、组合和表示的场景,或者系统需要配置多个产品系列之一的场景。

4.3、工厂模式的实现方式

(1)如何实现简单工厂模式?
简单工厂模式通常通过一个工厂类来创建对象,该类包含一个静态方法,该方法根据传入的参数返回相应的对象实例。
(2)如何实现工厂方法模式?
工厂方法模式通过定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
(3)如何实现抽象工厂模式?
抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。客户端使用抽象工厂来创建具体工厂的子类,从而创建一系列相关对象。

4.4、工厂模式与其他设计模式的对比

(1)工厂模式与单例模式的区别是什么?
工厂模式用于创建对象,而单例模式用于确保一个类只有一个实例,并提供一个全局访问点。
(2)工厂模式与建造者模式的区别是什么?
工厂模式注重于对象的创建过程,而建造者模式则注重于复杂对象的构建过程。建造者模式通过构建一个复杂对象的各个部分来表示其创建过程,并通过一个导演类来管理这些部分的构建顺序。
(3)工厂模式与原型模式的区别是什么?
工厂模式通过实例化类来创建对象,而原型模式则通过复制现有对象来创建新对象。原型模式通过实现一个原型接口,允许对象通过复制自身来创建新的实例。

4.5、工厂模式的优缺点

(1)工厂模式的优点有哪些?
工厂模式将对象的创建过程封装在工厂类中,实现了对象的创建与使用的分离。
工厂模式提高了系统的可扩展性和灵活性,使得系统可以轻松地添加新产品或修改现有产品。
工厂模式有助于减少客户端代码对具体产品类的依赖,降低了系统的耦合度。
(2)工厂模式的缺点有哪些?
工厂模式可能会增加系统的复杂性,因为需要引入额外的工厂类和接口。
在某些情况下,工厂模式可能会导致性能下降,因为需要额外的步骤来创建对象。

5、总结

综上所述,三种工厂模式各有其独特的应用场景和优势。在实际应用中,应根据系统的具体需求和特点来选择合适的工厂模式,以实现代码的高内聚、低耦合和可扩展性。

6、参考文章

6.1 C++之工厂(factory)模式


http://www.ppmy.cn/embedded/148636.html

相关文章

java 核心知识点——JVM

目录 什么是Java虚拟机&#xff1f; 虚拟机架构设计 为什么用元空间取代永久代 双亲委派机制 分代年龄为什么是15次 GC算法 如何判断一个对象可以被回收 什么是Java虚拟机&#xff1f; Java virtual machine。虚拟机&#xff0c;像真实的计算机一样&#xff0c;能够运行…

thinkphp6使用MongoDB多个数据,聚合查询的坑

我使用的是thinkphp6,mongodb4.0实际业务查询 $list Db::connect(tstd_mongo)->table("$table_time.Item")->where($where)->order("Cause","asc")->field(_id,DBID,Data,GSID,MainKind,ManID,DISTINCT(Serial) Serial,SubKind,Tim…

VisionPro开发使用交互反馈系统(Affordance System)

XR Interaction Toolkit 提供了一个affordance system 可供性系统&#xff0c;使用户能够创建对交互状态的视觉和听觉反馈。一般的信息流从向Affordance State Provider场景中添加一个&#xff08;通常是可交互的&#xff09;并将其指向我们要监视其交互状态的可交互对象开始。…

docker部署微信小程序自动构建发布和更新

通过 Jenkins 和 Docker 部署微信小程序&#xff0c;并实现自动构建、发布和版本更新&#xff0c;主要涉及以下几个步骤&#xff1a; 设置 Jenkins 环境配置 GitLab 与 Jenkins 的集成构建 Docker 镜像部署和发布微信小程序配置 Jenkins 自动构建 以下是详细的步骤说明&#…

embeding 层到底是什么

embending 的本质是 word2vec 大白话讲解word2vec到底在做些什么 那时候 博主还比较年轻 &#xff0c;啃过托马斯马尔科夫的 word2vec 源码 ,那是一个三层神经网络&#xff0c;用C实现的 &#xff0c;最近创业失败了 &#xff0c;又去找工作&#xff0c;啥都不会&#xff0c;被…

小红书关键词搜索采集 | AI改写 | 无水印下载 | 多维表格 | 采集同步飞书

小红书关键词搜索采集 | AI改写 | 无水印下载 | 多维表格 | 采集同步飞书 一、下载影刀&#xff1a; https://www.winrobot360.com/share/activity?inviteUserUuid595634970300317698 二、加入应用市场 https://www.yingdao.com/share/accede/?inviteKeyb2d3f22a-fd6c-4a…

w113健身房管理系统

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

Python基础学习的资料

一、Python简介 Python是一种高级、解释型、通用的编程语言。它由Guido van Rossum于1989年开始开发&#xff0c;第一个公开发行版发行于1991年。 特点 简洁易读 Python代码简洁明了&#xff0c;采用缩进的方式来表示代码块&#xff0c;而不是像其他语言使用大括号。例如&…