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

news2024/9/23 1:30:42

系列文章

可跳转到下面链接查看下表所有内容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.coloradmin.cn/o/1930074.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

redis原理之底层数据结构(三)-quicklist

1.绪论 前面讲过的ziplist在查找元素的时候是o(n)的复杂度&#xff0c;如果ziplist长度太长&#xff0c;会导致查找元素很缓慢&#xff0c;而ziplist是拥有内存连续的优势&#xff0c;为了保留ziplist内存连续的优势&#xff0c;但是又不能保留太长的长度&#xff0c;我们出现…

MQ基础1

对应B站视频&#xff1a; MQ入门-01.MQ课程介绍_哔哩哔哩_bilibili 微服务一旦拆分&#xff0c;必然涉及到服务之间的相互调用&#xff0c;目前我们服务之间调用采用的都是基于OpenFeign的调用。这种调用中&#xff0c;调用者发起请求后需要等待服务提供者执行业务返回结果后…

【Linux杂货铺】期末总结篇3:用户账户管理命令 | 组账户管理命令

&#x1f308;个人主页&#xff1a;聆风吟_ &#x1f525;系列专栏&#xff1a;Linux杂货铺、Linux实践室 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 第五章5.1 ⛳️Linux 账户5.2 ⛳️用户配置文件和目录&#xff08;未完待续&#xff09;5.2.1 …

java面向对象进阶篇--static

一、前言 java进阶篇已经开始了&#xff0c;先从面向对象开始&#xff0c;由于时间原因今天就只更新了static部分&#xff0c;内容上特别详细&#xff0c;一些特别的注意事项也在反复的提醒大家。 温馨提示一下&#xff0c;往后的java篇会越来越难&#xff0c;希望大家能够坚…

推荐5个实用的可视化工具

面对海量的数据&#xff0c;我们应该如何高效地提取其价值&#xff0c;让复杂的信息一目了然&#xff1f;这正是可视化工具大显身手的舞台。今天&#xff0c;我就来分享几款非常好用的数据可视化工具&#xff0c;它们不仅能够帮助你轻松驾驭数据&#xff0c;还能让你的工作汇报…

vite配置环境变量和使用,配置正确后import.meta.env.VITE_APP_BASE_URL编译报错的解决方法

一、配置&#xff1a; 1.新增四个环境文件 .env.development .env.test .env.production .env.pre 内容为不同环境的不同参数变量必须以VITE_APP开头&#xff0c;如&#xff1a; #接口地址 VITE_APP_BASE_URL"&#xffe5;&#xffe5;&#xffe5;&#xffe5;&#xff…

算法 —— 快速幂

目录 P1045 [NOIP2003 普及组] 麦森数 P1226 【模板】快速幂 原理I 原理II P1226 代码解析 P1045 代码解析 P1045 [NOIP2003 普及组] 麦森数 本题来自洛谷&#xff1a;P1045 [NOIP2003 普及组] 麦森数&#xff0c;根据题意&#xff0c;我们可以看到本题需要计算最少2的1…

【Linux】权限的管理和Linux上的一些工具

文章目录 权限管理chgrpchownumaskfile指令sudo指令 目录权限粘滞位Linux中的工具1.软件包管理器yum2.rzsz Linux开发工具vim 总结 权限管理 chgrp 功能&#xff1a;修改文件或目录的所属组 格式&#xff1a;chgrp [参数] 用户组名 文件名 常用选项&#xff1a;-R 递归修改文…

Host碰撞实验

目录 Host碰撞原理 Host碰撞判断技巧 Host碰撞检测方法 Host碰撞实验步骤 从攻击者的视角来进行资产的梳理&#xff0c;采用全端口扫描子域名收集的方式&#xff0c;识别所有的企业资产暴露面。但即使是这样&#xff0c;往往会因为配置错误或是未及时回收等原因&#xff0c…

android13 frameworks里面常用的保存信息或者版本判断的方法

总纲 android13 rom 开发总纲说明 目录 1.前言 2. 数据库 2.1 代码读取用法参考 3.prop 属性配置 3.1 property的key值有哪些特点 4.区别 5. 其他数据存储 6.彩蛋 1.前言 frameworks 不像我们一般开发app那样,很多应用保存的方法都无法使用。这里记录我们系统rom开…

初学SpringMVC之 JSON 篇

JSON&#xff08;JavaScript Object Notation&#xff0c;JS 对象标记&#xff09;是一种轻量级的数据交换格式 采用完全独立于编程语言的文本格式来存储和表示数据 JSON 键值对是用来保存 JavaScript 对象的一种方式 比如&#xff1a;{"name": "张三"}…

ssh -D 选项用于动态(Dynamic)端口转发

举例实现不同ssh连接功能目录 一、功能简介 -D 支持 SOCKS5 协议&#xff0c;可以同时转发 TCP 和 UDP 报文 二、原理介绍 假设拥有三台主机&#xff0c;具体环境如下&#xff1a; 1. 主机 A&#xff1a;本地主机&#xff0c;即 SSH 客户 所在的主机&#xff0c;IP&#xff1…

Python游戏开发——天天酷跑(完整版教程)只需要200行代码就做出了一个天天酷跑小游戏,原来代码做游戏这么简单!零基础也能教你学会!

最近一段时间&#xff0c;小编发现已经好久没有给大家带来趣味游戏的案例展示了。刚好小编趁着周末写了一个《天天酷跑》的游戏&#xff0c;因此拿来跟大家一起分享&#xff0c;和大家一起来重温经典的酷跑游戏。 01 准备开发环境 俗话说&#xff0c;“工欲善其事&#xff0c…

详解:动画专业就业前景和就业方向

随着数字创意产业的蓬勃发展&#xff0c;动画专业已成为越来越多学子的选择。动画专业的就业前景日益广阔&#xff0c;不仅在游戏、影视、广告等传统领域有着广泛应用&#xff0c;还在建筑、教育、医学等多个行业展现出强大的潜力。 那么&#xff0c;何为动画专业呢&#xff1f…

快慢指针的应用(题目来源力扣oj训练)

快慢指针 快慢指针一般用来找到链表的中间节点&#xff0c;就是直接搞两个指针&#xff0c;快指针的移动是慢指针的两倍&#xff0c;那么为什么快慢指针可以找到中间节点&#xff0c;因为假设一个为n的链表&#xff0c;快指针走完慢指针也就是n/2。 具体案例 找链表的中间节…

【深度学习入门篇 ⑦】PyTorch池化层

【&#x1f34a;易编橙&#xff1a;一个帮助编程小伙伴少走弯路的终身成长社群&#x1f34a;】 大家好&#xff0c;我是小森( &#xfe61;ˆoˆ&#xfe61; ) &#xff01; 易编橙终身成长社群创始团队嘉宾&#xff0c;橙似锦计划领衔成员、阿里云专家博主、腾讯云内容共创官…

Windows 系统利用 SSH 和 WSL2 子系统当服务器

由于最近组内需要将一台 Windows 系统的电脑 W A W_A WA​ 转成能通过 SSH 访问&#xff0c;并且能用 Linux 命令当服务器运行。忙活了一天&#xff0c;终于是把全部东西弄通了。 安装 SSH 首先就是 W A W_A WA​ 先要安装 OpenSSH 服务&#xff0c;直接按照下面的教程安装…

LVS+Keepalive高可用

1、keepalive 调度器的高可用 vip地址主备之间的切换&#xff0c;主在工作时&#xff0c;vip地址只在主上&#xff0c;vip漂移到备服务器。 在主备的优先级不变的情况下&#xff0c;主恢复工作&#xff0c;vip会飘回到住服务器 1、配优先级 2、配置vip和真实服务器 3、主…

【Python实战因果推断】38_双重差分9

目录 Doubly Robust Diff-in-Diff Propensity Score Model Delta Outcome Model All Together Now Doubly Robust Diff-in-Diff 另一种纳入干预前协变变量和时间不变协变变量以考虑条件平行趋势的方法是制作双稳健差分法&#xff08;DRDID&#xff09;。要做到这一点&#…

鸿蒙语言基础类库:【@system.brightness (屏幕亮度)】

屏幕亮度 说明&#xff1a; 从API Version 7 开始&#xff0c;该接口不再维护&#xff0c;推荐使用新接口[ohos.brightness]。本模块首批接口从API version 3开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import brightness from sy…