【设计模式】【创建型模式】【02工厂模式】

系列文章

可跳转到下面链接查看下表所有内容https://blog.csdn.net/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501文章浏览阅读2次。系列文章大全https://blog.csdn.net/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501


目录

系列文章

1.简介

2.简单工厂模式

2.1 简介

2.1.1 组成结构

2.1.2 优点和缺点

2.1.3 应用场景

2.2 代码案例

2.2.1 主要步骤

2.2.2 代码

3.工厂方法模式

3.1简介

3.1.1 组成结构

3.1.2 优点和缺点

3.1.3 应用场景

3.2 代码案例

3.2.1 主要步骤

3.2.2 代码

4.抽象工厂模式

4.1简介

4.1.1 组成结构

4.1.2 优点和缺点

4.2 代码案例

4.2.1 主要步骤

4.2.2 代码

5.区别


1.简介

工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,即定义一个用于创建对象的接口,让子类决定应该实例化哪个类,使类的实例化延迟到子类。 也可以这样理解,
工厂模式可以分为三类:
1.简单工厂模式(Simple Factory)
2.工厂方法模式(Factory Method)
3.抽象工厂模式(Abstract Factory)

2.简单工厂模式

2.1 简介

简单工厂模式是通过一个工厂类将所有对象的创建封装起来,通过传入不同的参数,工厂负责创建不同的具体对象。

建立对象的类是工厂,被建立的对象是产品,使用产品的人无需关心这个产品是怎样生产的,这样便降低了模块之间的耦合。

2.1.1 组成结构

1.工厂类:用来创建所有产品,通过传入的type不同,从而创建不同的产品。例如:本节案例代码中的Factory类。

2.抽象产品类:它一般是具体产品继承的父类或者实现的接口。例如:本节案例代码中的Car类。

3.具体产品类此类继承抽象产品类,自工厂类所创建的对象就是此角色的实例。例如:本节案例代码中的CarA类和CarB类。

特点:一个工厂生产所有的具体产品。

2.1.2 优点和缺点

优点:
1.将所有对象的创建集合到了一个工厂类中,客户端只需要调用工厂类的接口,传入不同的参数,而无需关注具体对象的创建过程。

2.可以通过工厂类创建不同的对象,而客户端无需改动,实现了客户端和具体所有对象的解耦,提高了代码的灵活性。
缺点:
1.每新增一个产品,则需要修改工厂类的逻辑,违反了开闭原则。
2.当产品足够多的时候,代码会过于臃肿,不利于维护。

2.1.3 应用场景

1.需要根据不同的参数类型创建不同的对象时。

2.2 代码案例

当前代码场景:

我们现在一个工厂要生产车型A和车型B

2.2.1 主要步骤

第一步:创建抽象产品类Car和创建抽象run函数
第二步:创建具体产品类车型A(CarA),实现其抽象run函数。
第三步:创建具体产品类车型B(CarB),实现其抽象run函数
第四步:创建工厂类Factory,并书写根据不同参数创建不同车型的createCar方法。
第五步:客户端(此例是main.cpp调用)创建工厂类对象,通过传递不同的参数,工厂创建不同的对象并返回给客户。

2.2.2 代码

// 抽象产品类
class Car
{

public:
    virtual void run() = 0; // 抽象共同接口
    string cartype;
};

// 具体产品类:车A
class CarA : public Car
{

public:
    CarA()
    {
        cartype = "A 车";
    }
    virtual void run()
    {
        std::cout << "this is cartype = " << cartype << endl;
    }
};

// 具体产品类:车B
class CarB : public Car
{

public:
    CarB()
    {
        cartype = "B 车";
    }
    virtual void run()
    {
        std::cout << "this is cartype = " << cartype << endl;
    }
};

// 工厂类
class Factory
{
public:
    Car *createCar(int type)
    {
        switch (type)
        {
        case CAR_TYPE_A:
            return new CarA();
            break;
        case CAR_TYPE_B:
            return new CarB();
            break;
        default:
            return nullptr;
            break;
        }
    }
};

int main()
{
    Factory *mFactory = new Factory();           // c创建工厂类
    Car *acar = mFactory->createCar(CAR_TYPE_A); // 根据具体的参数创建对应的对象,此处是父类指针指向子类对象
    Car *bcar = mFactory->createCar(CAR_TYPE_B);
    acar->run();
    bcar->run();

    // 注意析构
    delete acar;
    delete bcar;
    delete mFactory;
    return 0;
}

3.工厂方法模式

3.1简介

工厂方法模式在简单工厂模式的基础上,去掉了简单工厂模式中的创建所有对象的方法,并提供了一个抽象生产产品的接口,并使其它可以被子类继承。这样在简单工厂模式里集中在工厂方法上的压力可以由工厂方法模式里不同的工厂子类来分担。
简单工厂模式的特点是一个工厂只生产所有产品,而工厂方法模式则是一个工厂只生产一个产品,这样当生产产品的时候,只需要确定是哪个工厂即可。

3.1.1 组成结构

1.抽象工厂类:是具体工厂类的父类,其包含一个具体工厂类必须实现的抽象接口。例如:本节案例代码的Factory类,抽象接口是createCar函数。
2.具体工厂类:对应其具体产品,用以创建对应的具体产品的对象。例如:本节案例代码的工厂A和工厂B,工厂A负责生产车型A, 工厂B负责生产车型B。
3.抽象产品类:它是具体产品继承的父类。例如:本节案例代码的Car类。
4.具体产品类:具体工厂类所创建的对象就是此类的实例。例如:本节案例代码的车型A类和车型B类。

3.1.2 优点和缺点

优点:
1.当需要增加新的工厂和产品的时候,可以不用更改现有代码,增加了代码的可扩展性,将对象的创建和使用进行了解耦。
缺点:
1.当产品种类过多时,由于每一种产品都需要实现一个工厂类,增加代码复杂性。

3.1.3 应用场景

当只有一类产品时。同时客户端需要生成不同的对象。

3.2 代码案例

此时场景为:
A工厂生产车型A,B工厂生产车型B

3.2.1 主要步骤

第一步:创建抽象产品类(Car类)。

第二步:创建抽象产品类的两个子类(CarA类和CarB类),其子类是具体产品类。

第三步:创建抽象工厂类(Factory类),并提供生产对象的抽象接口。

第四步:创建两个具体工厂类,一个是生产CarA的工厂类,一个是生产CarB的工厂类,并实现抽象方法,创建不同的产品对象。

第五步:客户端(此例是main.cpp调用)创建不同的工厂类对象,从而创建出多个不同的产品对象。

3.2.2 代码

// 抽象产品类
class Car
{

public:
    virtual void run() = 0; // 抽象共同接口
    string cartype;
};

// 具体产品类:车A
class CarA : public Car
{

public:
    CarA()
    {
        cartype = "A 车";
    }
    virtual void run()
    {
        std::cout << "this is cartype = " << cartype << endl;
    }
};

// 具体产品类:车B
class CarB : public Car
{

public:
    CarB()
    {
        cartype = "B 车";
    }
    virtual void run()
    {
        std::cout << "this is cartype = " << cartype << endl;
    }
};

// 抽象工厂类
class Factory
{
public:
    virtual Car *createCar() = 0;
};

// 具体工厂类:工厂A(对应产品A)
class FactoryA : public Factory
{
public:
    virtual Car *createCar()
    {
        return new CarA();
    }
};
// 具体工厂类:工厂B(对应产品B)
class FactoryB : public Factory
{
public:
    virtual Car *createCar()
    {
        return new CarB();
    }
};

int main()
{
    Factory *mFactoryA = new FactoryA(); // 创建具体工厂类A
    Car *acar = mFactoryA->createCar();  // 根据具体的工厂类创建对应的对象,此处是父类指针指向子类对象
    acar->run();
    Factory *mFactoryB = new FactoryB(); // 创建具体工厂类B
    Car *bcar = mFactoryB->createCar();  // 根据具体的工厂类创建对应的对象,此处是父类指针指向子类对象
    bcar->run();

    // 注意析构
    delete acar;
    delete bcar;
    delete mFactoryA;
    delete mFactoryB;
    return 0;
}

4.抽象工厂模式

之前的工厂方法模式一个工厂只生产一个产品,而在实际生活中,通过一个工厂会生产多种产品,比如:车的组成需要轮胎和方向盘,那么当出现多个产品的时候,便需要使用抽象工厂模式。

4.1简介

提供一个创建一系列相关或相互依赖的对象接口,而无需指定它们的具体类。其实抽象工厂模式就是多个工厂方法模式,只是因为工厂方法是一个工厂只创建一个产品,而抽象工厂模式是一个工厂创建多个产品。

4.1.1 组成结构

抽象工厂类:是具体工厂类的父类,其内部定义了创建多个产品对象的抽象接口,必须由具体工厂类实现。
例如:本节代码案例中的Factory类,抽象接口为createTire和createWheel。

具体工厂类:对应其具体产品,用以创建对应的具体产品的对象。
例如:本节代码案例中的 具体工厂(工厂白色)和具体工厂(工厂黑色)。

抽象产品类:定义了产品的共同接口,具体的产品类必须实现这个接口。工厂模式会由多个产品,因此抽象产品类也是多个。
例如:本节代码案例中的第一个抽象产品类(轮胎)和第二个抽象产品类(方向盘)。

具体产品类:是抽象工厂模式中具体创建的对象。
例如:本节代码案例中的白轮胎和黑轮胎,白方向盘和黑方向盘。

4.1.2 优点和缺点

优点:
创建产品族,将一系列的产品族,统一到一起进行创建
缺点:
扩展困难,当产品族中有新产品,比如新增发动机产品时,需要修改抽象工厂的接口。

4.2 代码案例

现在场景为:
白色工厂需要生产白色轮胎和白色方向盘。
黑色工厂需要生产黑色轮胎和黑色方向盘。
白色系列产品由白色工厂统一管理。
黑色系列产品由黑色工厂统一管理。

4.2.1 主要步骤

第一步:创建第一个抽象产品类(轮胎类)。

第二步:创建第一个抽象产品类的两个子类(白轮胎类和黑轮胎类),其子类是具体产品类。

第三步:创建第二个抽象产品类(方向盘类)。

第四步:创建第二个抽象产品类的两个子类(白方向盘类和黑方向盘类),其子类是具体产品类。

第五步:创建抽象工厂类(Factory类),并提供生产所有对象的两个抽象接口。

第六步:创建两个具体工厂类,一个是生产白色产品的白色工厂类,一个是生产黑色产品的白色工厂类,并实现两个抽象方法,创建不同的产品对象。

第七步:客户端(此例是main.cpp调用)创建不同的工厂类对象,从而创建出多个不同的产品对象。

4.2.2 代码

// 第一个抽象产品类:轮胎
class Tire
{

public:
    virtual void whcihtype() = 0;
    string Tiretype;
};

// 第一个抽象产类的第一个具体产品类:白轮胎
class WhiteTire : public Tire
{

public:
    WhiteTire()
    {
        Tiretype = "白色轮胎";
    }
    virtual void whcihtype()
    {
        std::cout << "this is Tiretype = " << Tiretype << endl;
    }
};

// 第一个抽象产类的第二个具体产品类:黑轮胎
class BlackTire : public Tire
{

public:
    BlackTire()
    {
        Tiretype = "黑色轮胎";
    }
    virtual void whcihtype()
    {
        std::cout << "this is Tiretype = " << Tiretype << endl;
    }
};

// 第二个抽象产品类:方向盘
class Wheel
{
public:
    virtual void whcihtype() = 0;
    string Wheeltype;
};

// 第二个抽象产类的第一个具体产品类:白色方向盘
class WhiteWheel : public Wheel
{

public:
    WhiteWheel()
    {
        Wheeltype = "白色方向盘";
    }
    virtual void whcihtype()
    {
        std::cout << "this is Wheeltype = " << Wheeltype << endl;
    }
};

// 第二个抽象产类的第二个具体产品类:黑色方向盘
class BlackWheel : public Wheel
{

public:
    BlackWheel()
    {
        Wheeltype = "黑色方向盘";
    }
    virtual void whcihtype()
    {
        std::cout << "this is Wheeltype = " << Wheeltype << endl;
    }
};

// 抽象工厂类
class Factory
{
public:
    virtual Tire *createTire() = 0; // 抽象接口
    virtual Wheel *createWheel() = 0;
};

// 具体工厂类:工厂白色(对应生产白色轮胎和白色方向盘)
class FactoryWhite : public Factory
{
public:
    virtual Tire *createTire()
    {
        return new WhiteTire(); // 生产白轮胎
    }

    virtual Wheel *createWheel()
    {
        return new WhiteWheel(); // 生产白方向盘
    }
};

// 具体工厂类:工厂黑色(对应生产黑色轮胎和黑色方向盘)
class FactorBlock : public Factory
{
public:
    virtual Tire *createTire()
    {
        return new BlackTire(); // 生产黑轮胎
    }

    virtual Wheel *createWheel()
    {
        return new BlackWheel(); // 生产黑方向盘
    }
};

int main()
{
    Factory *mFactoryWhite = new FactoryWhite();    // 创建具体工厂类:工厂白色
    Tire *mWhiteTire = mFactoryWhite->createTire(); // 创建白色轮胎
    mWhiteTire->whcihtype();
    Wheel *mWhiteWheel = mFactoryWhite->createWheel(); // 创建白色方向盘
    mWhiteWheel->whcihtype();

    Factory *mFactoryBlock = new FactorBlock();     // 创建具体工厂类:工厂黑色
    Tire *mBlockTire = mFactoryBlock->createTire(); // 创建黑色轮胎
    mBlockTire->whcihtype();
    Wheel *mBlockWheel = mFactoryBlock->createWheel(); // 创建黑色方向盘
    mBlockWheel->whcihtype();

    // 注意析构
    delete mFactoryWhite;
    delete mWhiteTire;
    delete mWhiteWheel;
    delete mFactoryBlock;
    delete mBlockTire;
    delete mBlockWheel;

    return 0;
}

5.区别

简单工厂模式:
一个抽象产品类,可以派生出多个具体产品类。
无抽象工厂类,只有一个工厂类,此工厂类负责生产所有产品。

工厂方法模式:
一个抽象产品类,可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类只能创建一个具体产品类的实例。

抽象工厂模式:
多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
一个抽象工厂类,可以派生出多个具体工厂类。
每个具体工厂类可以创建多个具体产品类的实例。

总结:

抽象产品类:工厂方法模式和简单工厂模式都只有一个抽象产品类,而抽象工厂模式有多个。

具体产品类:工厂方法模式和简单工厂模式都只能有一个抽象产品类派生出多个具体产品类,而抽象工厂模式可以从多个抽象产品类派生出多个具体产品类。

抽象工厂类:工厂方法模式和抽象工厂模式都有一个抽象工厂类,而简单工厂模式没有。

具体工厂类:简单工厂模式只有一个工厂类,而工厂方法模式和抽象工厂模式可以有多个具体工厂类。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。

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

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

相关文章

pico+unity3d手部动画

在 Unity 开发中&#xff0c;输入系统的选择和运用对于实现丰富的交互体验至关重要。本文将深入探讨 Unity 中的 Input System 和 XR Input Subsystem 这两种不同的输入系统&#xff0c;并详细介绍它们在控制手部动画方面的应用。 一、Input System 和 XR Input Subsystem 的区…

【Linux 配置静态IP】Ubuntu20.04

最近学习网络编程&#xff0c;为了方便学习需要Ubuntu配置静态IP&#xff0c;网上看了好多贴子跟着试了下可以实现&#xff0c;但重启虚拟机后有时就无法连接&#xff0c;总之各种各样问题&#xff1b;相关的配置方法也比较凌乱&#xff0c;有用netplan 或者 ifupdown ,笔者简单…

使用LobeChat+Ollama快速搭建本地大模型,离线可用

文章目录 准备工作下载Ollama什么是Ollama 参考文献 分享一下如何部署本地大模型&#xff0c;让它成为你的离线助手。 准备工作 服务器或者电脑一台&#xff0c;配置越高越好&#xff0c; Windows和Mac皆可&#xff0c;Widows最好内存8G以上而且带一块好一点的显卡&#xff1b…

AI伦理议题:从隐私保护到算法公平

文章目录 &#x1f34a;1 人工智能兴起背后的伦理及道德风险1.1 算法偏见与歧视1.2 数据隐私侵权1.3 透明度受限1.4 决策失衡1.5 AI生成内容的危险性 &#x1f34a;2 建构AIGC伦理观&#xff1a;实现人机共创的永续提升2.1 技术手段与伦理预防2.2 即时警告与紧急关停措施2.3 法…

Qt 使用Installer Framework制作安装包

Qt 使用Installer Framework制作安装包 引言一、下载安装 Qt Installer Framework二、简单使用2.1 创建目录结构 (文件夹结构)2.2 制作程序压缩包2.3 制作程序安装包 引言 Qt Installer Framework (安装程序框架)是一个强大的工具集&#xff0c;用于创建自定义的在线和离线安装…

【Outlook】从Outlook新版回归经典版全攻略

引言 在微软宣布计划于2024年底淘汰邮件应用&#xff08;Mail app&#xff09;之后&#xff0c;许多用户发现新版Outlook应用&#xff08;Outlook (new)&#xff09;在他们的Windows 11/10系统上自动启动。如果您更倾向于使用经典版Outlook&#xff08;Outlook (classic)&…

【tomcat】Tomcat如何扩展Java线程池原理

池化技术 在后端中&#xff0c;对于经常使用池化就是来提升系统性能&#xff0c;比如数据库连接池、线程池连接池等&#xff0c;本质都是利用空间换时间的来提升性能&#xff0c;用来避免资源的频繁创建和销毁&#xff0c;以此提高资源的复用率&#xff0c;所以合理设置系统所…

Python | Leetcode Python题解之第233题数字1的个数

题目&#xff1a; 题解&#xff1a; class Solution:def countDigitOne(self, n: int) -> int:# mulk 表示 10^k# 在下面的代码中&#xff0c;可以发现 k 并没有被直接使用到&#xff08;都是使用 10^k&#xff09;# 但为了让代码看起来更加直观&#xff0c;这里保留了 kk,…

成为CMake砖家(5): VSCode CMake Tools 插件基本使用

大家好&#xff0c;我是白鱼。 之前提到过&#xff0c;白鱼的主力 编辑器/IDE 是 VSCode&#xff0c; 也提到过使用 CMake Language Support 搭配 dotnet 执行 CMakeLists.txt 语法高亮。 对于阅读 CMakeLists.txt 脚本&#xff0c; 这足够了。 而在 C/C 开发过程中&#xff…

完美的用户体验:如何设计一个直观和有效的网站导航?

APP的顶部导航栏对我们来说很熟悉。导航栏是UI设计中不可或缺的一部分&#xff0c;几乎每个页面都使用导航栏。虽然导航栏看起来很简单&#xff0c;不需要太多精力&#xff0c;但是设计一个与产品需求和客户目标高度匹配的导航栏并不是那么容易的。导航栏的设计标准有很多细节需…

qt 创建一个左侧边线拖拽的矩形

1.概要 2.代码 2.1 代码第一版 在Qt中&#xff0c;要创建一个可以向左侧拖拽边线的矩形&#xff0c;你需要自定义一个QGraphicsRectItem的子类&#xff0c;并重写其事件处理函数来响应鼠标的拖拽动作。以下是一个简单的实现示例&#xff1a; #include <QApplication>…

Python酷库之旅-第三方库Pandas(028)

目录 一、用法精讲 71、pandas.tseries.api.guess_datetime_format函数 71-1、语法 71-2、参数 71-3、功能 71-4、返回值 71-5、说明 71-6、用法 71-6-1、数据准备 71-6-2、代码示例 71-6-3、结果输出 72、pandas.util.hash_array函数 72-1、语法 72-2、参数 72…

快速排序及归并排序的实现与排序的稳定性

目录 快速排序 一. 快速排序递归的实现方法 1. 左右指针法 步骤思路 为什么要让end先走&#xff1f; 2. 挖坑法 步骤思路 3. 前后指针法 步骤思路 二. 快速排序的时间和空间复杂度 1. 时间复杂度 2. 空间复杂度 三. 快速排序的优化方法 1. 三数取中优化 2. 小区…

昇思25天学习打卡营第13天|munger85

文本解码原理–以MindNLP为例 重要的就是怎么样把数字最后转化成真正的文字。而且自回归模型它会一个字给一个字的预测&#xff0c;下一个字应该是什么&#xff1f; 如果这个模型下载很慢&#xff0c;你就可以通过这种方式从摩大社区进行下载。 这种方式&#xff0c; 每一次候…

AI+文娱,人工智能助力文娱行业智能化之路!

近些年来&#xff0c;我国文化产业领域对于人工智能等高新科技愈发重视&#xff0c;呈现出文化和科技深度有机融合的发展态势。科技与文化碰撞带来的火花&#xff0c;让我们对历史的表达有了更多可能。这既是高新技术的具体应用和不断落地&#xff0c;也是提升文化产品数字化、…

MFC CRectTracker 类用法详解

CRectTracker 类并非 Microsoft Foundation Class (MFC) 库中应用很广泛的一个类&#xff0c;一般教科书中很少有提到。在编程中如果需编写选择框绘制以及选择框大小调整、移动等程序时&#xff0c;用CRectTracker 类就会做到事半而功倍。下面详细介绍MFC CRectTracker 类。 M…

小熊猫C++与Dev-C++:两款C++开发环境的对比

引言 在C编程的世界中&#xff0c;选择合适的开发环境是至关重要的。今天&#xff0c;我们将对比两款流行的C开发工具&#xff1a;小熊猫C和Dev-C。这两款软件各有特色&#xff0c;适合不同的编程需求和偏好。本文将从多个方面对它们进行详细的比较&#xff0c;帮助开发者做出…

如何追查一个packet在linux 系统哪里丢失

要想追一个包在系统哪里丢失了&#xff0c; 就要了解 一个应用层的包在送出时 要经历那些 检查点 和被丢掉的点。 1. 在传输层&#xff0c;如果是 tcp 包 会有contrack 的 buf 的限制 可能会导致 packets 的丢失。 > 检查办法&#xff1a;查看dmesg日志有报错&#xff1a;k…

输入网址到网页显示的过程

输入网址到网页显示的过程 1. 浏览器解析 URL2. 域名解析解析的流程 3. TCP通过三次握手建立连接4. 生成TCP段&#xff1a;在数据的前面加上 TCP 头部&#xff0c;生成TCP段TCP 头部 5. 生成IP数据报&#xff1a;在TCP段的前面加上 IP包头&#xff0c;生成IP数据报IP包头 6. 在…

【时时三省】tessy 集成测试:小白入门指导手册

目录 1,创建集成测试模块且分析源文件 2,设置测试环境 3,TIE界面设置相关函数 4,SCE界面增加用例 5,编辑数据 6,用例所对应的测试函数序列 7,添加 work task 函数 8,为测试场景添加函数 9,为函数赋值 10,编辑时间序列的数值 11,执行用例 12,其他注意事项…