当前位置: 首页 > article >正文

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

文章目录

  • 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和adidasProducer

    return 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.kler.cn/a/451607.html

相关文章:

  • 京东科技基于 Apache SeaTunnel 复杂场景适配 #数据集成
  • 软件测试之全链路压测详解
  • VSCode 性能优化指南:提高编码效率,减少资源占用
  • 在 Ubuntu 上安装 VS Code
  • OpenResty开发环境搭建
  • 【前端】入门指南:Vue中使用Node.js进行数据库CRUD操作的详细步骤
  • 抖音视频下载去水印工具推荐
  • DATAHUB FRONTEND 开发测试:
  • WebGIS实战开源项目:智慧机场三维可视化(学习笔记)
  • “开启智能新时代”——机器连接与边缘计算
  • 微信小程序:解决顶部被遮挡的问题
  • Python8-写一些小作业
  • QT的错误记录:同文件的的两个QThread子类信号槽关联
  • MySQL for update skip locked 与 for update nowait
  • vue前端编译报错解决方法
  • 007-spring-bean的相关配置(重要)
  • 2025人工智能与教育科学国际会议(AIES 2025)
  • stm32硬件iic
  • Java中classpath的基本概念和配置方法
  • 【C#】可以点击单行文本的Popup控件
  • 如何使用Python调用SD模型进行文生图
  • 仓颉编程语言深入教程:基础概念和数据类型
  • [SZ901]FPGA程序固化工具使用方法
  • 国产之光--仓颉编程语言的实战案例分析
  • ESP32_H2(IDF)学习系列-ADC模数转换(连续转换)
  • 惠普HP proliant DL380 G6服务器使用