工厂模式(分简单工厂模式、工厂方法模式、抽象工厂模式)

2023-10-31

1、工厂模式概述:

1.1 简单工厂模式:

简单工厂模式是一种创建型设计模式,它实现了创建对象的功能,但不使用任何具体类的名称。客户端通过调用工厂类的静态方法来创建一个具体的对象,无需关心对象创建的细节。

1.2 工厂方法模式:

工厂方法模式是一种创建型设计模式,它提供了一个接口,用于创建对象,但将实际创建对象的过程推迟到子类中。这样,工厂方法模式允许在运行时根据需要动态地创建对象。

1.3 抽象工厂模式:

抽象工厂模式是一种创建型设计模式,它提供了一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。抽象工厂模式可以看作是工厂方法模式的泛化,它允许创建多个对象族。

2、工厂模式的适用场景:

  • 当需要在运行时创建多种类型的对象时,可以使用工厂模式。
  • 当需要将对象创建与使用分离时,可以使用工厂模式。
  • 当需要根据配置、用户输入或其他条件动态地创建对象时,可以使用工厂模式。
2.1 简单工厂模式:

适用于创建相对简单的对象,具有相似的构造过程。例如,一个简单的图形绘制工具,可以创建圆形、矩形和三角形等图形,可以使用简单工厂模式。

2.2 工厂方法模式:

适用于创建具有不同构造过程的对象,需要在运行时根据不同条件创建对象。例如,不同类型的日志记录器,如文件日志记录器、数据库日志记录器等,可以使用工厂方法模式。

2.3 抽象工厂模式:

适用于创建具有相互依赖关系的对象族。例如,跨平台的 GUI 工具箱,需要为不同平台(如 Windows、macOS、Linux)创建一系列相关的 GUI 组件,可以使用抽象工厂模式。

3、工厂模式的优点:

  • 将对象的创建和使用分离,降低了客户端与具体产品类之间的耦合,提高了代码的可维护性。
  • 可以在运行时动态地创建对象,增加了系统的灵活性。
  • 当新增或修改产品类时,客户端代码不需要进行修改,符合开放封闭原则。

4、工厂模式的缺点:

  • 当产品种类较多时,工厂类的代码可能变得复杂,难以维护。
  • 当需要新增产品时,可能需要修改工厂类的代码,这可能会违反开放封闭原则。
  • 抽象工厂模式可能导致大量的类和接口,增加了系统的复杂性。

5、 用C++实现一个简单工厂模式:

#include <iostream>
#include <memory>

class Shape {
public:
    virtual void draw() = 0;
};

class Circle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Circle" << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Rectangle" << std::endl;
    }
};

class ShapeFactory {
public:
    enum class ShapeType { Circle, Rectangle };

    static std::unique_ptr<Shape> createShape(ShapeType type) {
        switch (type) {
            case ShapeType::Circle:
                return std::make_unique<Circle>();
            case ShapeType::Rectangle:
                return std::make_unique<Rectangle>();
            default:
                return nullptr;
        }
    }
};

int main() {
    auto circle = ShapeFactory::createShape(ShapeFactory::ShapeType::Circle);
    circle->draw();
    auto rectangle = ShapeFactory::createShape(ShapeFactory::ShapeType::Rectangle);
    rectangle->draw();
    return 0;
}

在这个例子中,我们定义了一个 Shape 接口,以及 Circle 和 Rectangle 类,它们分别实现了 Shape 接口。接着,我们创建了一个 ShapeFactory 类,它提供了一个静态方法 createShape,根据输入的枚举类型来创建相应的 Shape 对象。最后,在 main 函数中,我们使用 ShapeFactory 创建了 Circle 和 Rectangle 对象,并调用它们的 draw 方法。

6、用C++实现一个工厂方法模式:

#include <iostream>
#include <memory>

class Shape {
public:
    virtual void draw() = 0;
};

class Circle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Circle" << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Rectangle" << std::endl;
    }
};

class ShapeFactory {
public:
    virtual std::unique_ptr<Shape> createShape() = 0;
};

class CircleFactory : public ShapeFactory {
public:
    std::unique_ptr<Shape> createShape() override {
        return std::make_unique<Circle>();
    }
};

class RectangleFactory : public ShapeFactory {
public:
    std::unique_ptr<Shape> createShape() override {
        return std::make_unique<Rectangle>();
    }
};

int main() {
    CircleFactory circleFactory;
    auto circle = circleFactory.createShape();
    circle->draw();

    RectangleFactory rectangleFactory;
    auto rectangle = rectangleFactory.createShape();
    rectangle->draw();

    return 0;
}

在这个例子中,我们沿用了之前的 Shape 接口和实现类。接着,我们创建了一个 ShapeFactory 接口,它提供了一个 createShape 方法。然后,我们为每个具体的 Shape 类创建了对应的工厂类(CircleFactory 和 RectangleFactory),它们分别实现了 ShapeFactory 接口。最后,在 main 函数中,我们使用 CircleFactory 和 RectangleFactory 创建了 Circle 和 Rectangle 对象,并调用了它们的 draw 方法。

7、用C++实现一个抽象工厂模式:

#include <iostream>
#include <memory>

class Button {
public:
    virtual void click() = 0;
};

class Checkbox {
public:
    virtual void check() = 0;
};

class WindowsButton : public Button {
public:
    void click() override {
        std::cout << "Windows Button clicked" << std::endl;
    }
};

class WindowsCheckbox : public Checkbox {
public:
    void check() override {
        std::cout << "Windows Checkbox checked" << std::endl;
    }
};

class MacOSButton : public Button {
public:
    void click() override {
        std::cout << "MacOS Button clicked" << std::endl;
    }
};

class MacOSCheckbox : public Checkbox {
public:
    void check() override {
        std::cout << "MacOS Checkbox checked" << std::endl;
    }
};

class GUIFactory {
public:
    virtual std::unique_ptr<Button> createButton() = 0;
    virtual std::unique_ptr<Checkbox> createCheckbox() = 0;
};

class WindowsGUIFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<WindowsButton>();
    }

    std::unique_ptr<Checkbox> createCheckbox() override {
        return std::make_unique<WindowsCheckbox>();
    }
};

class MacOSGUIFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<MacOSButton>();
    }

    std::unique_ptr<Checkbox> createCheckbox() override {
        return std::make_unique<MacOSCheckbox>();
    }
};

int main() {
    std::unique_ptr<GUIFactory> factory;

    // Assume we determine the platform at runtime.
    bool isWindows = true;
    if (isWindows) {
        factory = std::make_unique<WindowsGUIFactory>();
    } else {
        factory = std::make_unique<MacOSGUIFactory>();
    }

    auto button = factory->createButton();
    button->click();

    auto checkbox = factory->createCheckbox();
    checkbox->check();

    return 0;
}

在这个例子中,我们创建了两个接口:Button 和 Checkbox,分别表示不同的 GUI 组件。接着,我们创建了两个 Button 和 Checkbox 的实现类,分别表示 Windows 和 macOS 平台上的组件。然后,我们创建了一个 GUIFactory 接口,它提供了两个方法:createButton 和 createCheckbox,用于创建 Button 和 Checkbox 对象。接下来,我们为每个平台创建了对应的工厂类(WindowsGUIFactory 和 MacOSGUIFactory),它们分别实现了 GUIFactory 接口。最后,在 main 函数中,我们根据运行时的平台信息创建了一个工厂对象,并使用该工厂对象创建了 Button 和 Checkbox 对象。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

工厂模式(分简单工厂模式、工厂方法模式、抽象工厂模式) 的相关文章

  • 访问私人成员[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 通过将类的私有成员转换为 void 指针 然后转换为结构来访问类的私有成员是否合适 我认为我无权修改包含我需要访问的数据成员的类 如果不道德 我
  • 是否可以强制 XMLWriter 将元素写入单引号中?

    这是我的代码 var ptFirstName tboxFirstName Text writer WriteAttributeString first ptFirstName 请注意 即使我使用 ptFirstName 也会以双引号结束 p
  • Qt-Qlist 检查包含自定义类

    有没有办法覆盖加载自定义类的 Qt QList 的比较机制 即在 java 中你只需要重写一个比较方法 我有一个带有我的自定义类模型的 QList QList
  • 当我使用“control-c”关闭发送对等方的套接字时,为什么接收对等方的套接字不断接收“”

    我是套接字编程的新手 我知道使用 control c 关闭套接字是一个坏习惯 但是为什么在我使用 control c 关闭发送进程后 接收方上的套接字不断接收 在 control c 退出进程后 发送方的套接字不应该关闭吗 谢谢 我知道使用
  • 获取按下的按钮的返回值

    我有一个在特定事件中弹出的表单 它从数组中提取按钮并将标签值设置为特定值 因此 如果您要按下或单击此按钮 该函数应返回标签值 我怎样才能做到这一点 我如何知道点击了哪个按钮 此时代码返回 DialogResult 但我想从函数返回 Tag
  • WPF 中的调度程序和异步等待

    我正在尝试学习 WPF C 中的异步编程 但我陷入了异步编程和使用调度程序的困境 它们是不同的还是在相同的场景中使用 我愿意简短地回答这个问题 以免含糊不清 因为我知道我混淆了 WPF 中的概念和函数 但还不足以在功能上正确使用它 我在这里
  • 为什么#pragma optimize("", off)

    我正在审查一个 C MFC 项目 在某些文件的开头有这样一行 pragma optimize off 我知道这会关闭所有以下功能的优化 但这样做的动机通常是什么 我专门使用它来在一组特定代码中获得更好的调试信息 并在优化的情况下编译应用程序
  • 指针问题(仅在发布版本中)

    不确定如何描述这一点 但我在这里 由于某种原因 当尝试创建我的游戏的发布版本进行测试时 它的敌人创建方面不起作用 Enemies e level1 3 e level1 0 Enemies sdlLib 500 2 3 128 250 32
  • C - 找到极限之间的所有友好数字

    首先是定义 一对友好的数字由两个不同的整数组成 其中 第一个整数的除数之和等于第二个整数 并且 第二个整数的除数之和等于第一个整数 完美数是等于其自身约数之和的数 我想做的是制作一个程序 询问用户一个下限和一个上限 然后向他 她提供这两个限
  • Json.NET - 反序列化接口属性引发错误“类型是接口或抽象类,无法实例化”

    我有一个类 其属性是接口 public class Foo public int Number get set public ISomething Thing get set 尝试反序列化Foo使用 Json NET 的类给我一条错误消息
  • Cython 和类的构造函数

    我对 Cython 使用默认构造函数有疑问 我的 C 类 Node 如下 Node h class Node public Node std cerr lt lt calling no arg constructor lt lt std e
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • 如何返回 json 结果并将 unicode 字符转义为 \u1234

    我正在实现一个返回 json 结果的方法 例如 public JsonResult MethodName Guid key var result ApiHelper GetData key Data is stored in db as v
  • 如何将图像路径保存到Live Tile的WP8本地文件夹

    我正在更新我的 Windows Phone 应用程序以使用新的 WP8 文件存储 API 本地文件夹 而不是 WP7 API 隔离存储文件 旧的工作方法 这是我如何成功地将图像保存到 共享 ShellContent文件夹使用隔离存储文件方法
  • 将自定义元数据添加到 jpeg 文件

    我正在开发一个图像处理项目 C 我需要在处理完成后将自定义元数据写入 jpeg 文件 我怎样才能做到这一点 有没有可用的图书馆可以做到这一点 如果您正在谈论 EXIF 元数据 您可能需要查看exiv2 http www exiv2 org
  • for循环中计数器变量的范围是多少?

    我在 Visual Studio 2008 中收到以下错误 Error 1 A local variable named i cannot be declared in this scope because it would give a
  • 当操作繁忙时,表单不执行任何操作(冻结)

    我有一个使用 C 的 WinForms 应用程序 我尝试从文件中读取一些数据并将其插入数据表中 当此操作很忙时 我的表单冻结并且无法移动它 有谁知道我该如何解决这个问题 这可能是因为您在 UI 线程上执行了操作 将文件和数据库操作移至另一个
  • C++ fmt 库,仅使用格式说明符格式化单个参数

    使用 C fmt 库 并给定一个裸格式说明符 有没有办法使用它来格式化单个参数 example std string str magic format 2f 1 23 current method template
  • 为什么 C# Math.Ceiling 向下舍入?

    我今天过得很艰难 但有些事情不太对劲 在我的 C 代码中 我有这样的内容 Math Ceiling decimal this TotalRecordCount this PageSize Where int TotalRecordCount
  • Process.Start 阻塞

    我正在调用 Process Start 但它会阻止当前线程 pInfo new ProcessStartInfo C Windows notepad exe Start process mProcess new Process mProce

随机推荐

  • EWM100学习笔记(一)

    Unit 1 EWM与WM模块的差异 英文不太好 大概翻译了一部分内容 第一张大概介绍了一下WM与EWM各自的作用 最后总结了一下EWM相比WM的优势 SAP的常规操作 S 4后干脆就直接没有了WM模块 直接推EWM WM主要的功能 Tra
  • CSS-颜色属性+颜色函数+自定义变量

    最近更新时间 2017年5月8日16 08 13 我的博客地图 离开校园踏入职场 不是到达人生巅峰 而是人生才刚刚开始 校园里学的知识远不足工作需求 而且校园里的学习深度也比较浅显 因此 对于刚毕业前三年的工程师来说 马不停蹄不分昼夜的学习
  • 睿智的目标检测41——Pytorch搭建Retinanet目标检测平台

    睿智的目标检测41 Keras搭建Retinanet目标检测平台 学习前言 什么是Retinanet目标检测算法 源码下载 Retinanet实现思路 一 预测部分 1 主干网络介绍 2 从特征获取预测结果 3 预测结果的解码 4 在原图上
  • 思维模式

    1 整体思维 整体宏观的思考 2 反向思维 不断的问自己如果不这样 3 方法思维 不断的寻找方法 不断的提高自己 从知识范围 方法等宏观角度 还有特有技术方向
  • 字符输入流

    字符输入流 Character Input Stream 是用于从输入源 如文件 网络连接等 读取字符数据的流对象 在 Java 中 主要使用 java io Reader 及其子类来实现字符输入流的操作 FileReader 是 Java
  • uniapp 页面跳转的坑

    uniapp 页面跳转的坑 我们在使用 uniapp 的时候 经常使用到页面跳转 uniapp 的几个常用跳转我就不一一列表了 我就说我遇到的坑吧 如下图 我要从第一个页面跳到第二个页面 我在组件里面写的跳转 大家移位到下一张图 如下图 这
  • LaTex 使用特殊章节符号 (§)

    参考 LaTex 使用特殊章节符号 LaTex 使用特殊章节符号 在 tex文件开头 加上以下内容 usepackage utf8 inputenc usepackage cleveref crefname section Crefname
  • Android动画进阶指北

    原文链接 Android Animation Advanced Tricks 前面的文章介绍了动画的基本使用方法 本文来聊一聊涉及到动画的高级技巧 以及一些非常优质的学习资源和动画三方库和框架 页面之间的过渡动画 常规的动画都是针对某一页面
  • java配置文件中数据库密码加密

    最近 有位读者私信我说 他们公司的项目中配置的数据库密码没有加密 编译打包后的项目被人反编译了 从项目中成功获取到数据库的账号和密码 进一步登录数据库获取了相关的数据 并对数据库进行了破坏 虽然这次事故影响的范围不大 但是这足以说明很多公司
  • VScode使用pip已经下载了faker,但还是报错ModuleNotFoundError: No module named ‘faker‘

    修复一下pip python m ensurepip pip install faker 但是在安装faker的时候 出现了这样的情况 提示warning 换一种写法 pip install faker i http pypi douban
  • 给定一个介于0和1之间的实数,类型为double,打印它的二进制表示

    给定一个介于0和1之间的实数 0 625 类型为double 打印它的二进制表示 如果该数字无法精准地用32位以内的二进制表示 则打印 ERROR 先上代码 public class printbinary public static vo
  • ABAP DOI 技术

    用户提出的报表 是用EXCLE显示的 有许多特殊格式 比如 加粗 大小字体等 普通的ALV报表输出并不能满足用户的要求 那么只能用ALV与EXCLE的集成技术 目前已知的技术有两种 一种是OLE技术 用SMW0上传模板 然后填写数据 多数用
  • Springboot的pom.xml需要用到的依赖总结:

  • 蜣螂优化(DBO)算法(含MATLAB代码)

    先做一个声明 文章是由我的个人公众号中的推送直接复制粘贴而来 因此对智能优化算法感兴趣的朋友 可关注我的个人公众号 启发式算法讨论 我会不定期在公众号里分享不同的智能优化算法 经典的 或者是近几年提出的新型智能优化算法 并附MATLAB代码
  • python怎么生成词云图

    词云图是什么 词云图又称文字云 是信息可视化的表现形式之一 词云是把文本中出现频率较高的关键词进行视觉上的突出显示 形成关键词云层或关键词渲染 从而过滤掉大量的文本信息 读者可以快速领略文本的主旨 相对柱状图 折线图 饼图等用来显示数据的图
  • log4j2 JNDI注入漏洞问题复现

    最近大家应该都有被log4j2的JNDI注入漏洞搞的心烦意乱 当程序将用户输入的数据进行日志输出时 即可触发此漏洞 成功利用此漏洞可以在目标服务器上执行任意代码 以下为改问题的复现方法 1 首先下载JNDI Injection 起 RMI
  • 在docker里使用jupyterhub

    准备工作 需要先安装docker 具体方法参考我的上一篇文章 1 查看本地镜像docker images D go 练习 go zero demo gt docker images REPOSITORY TAG IMAGE ID CREAT
  • 程序切片知识点整理(程序依赖图、静态切片、动态切片)

    整理了很久很久的一篇文章 觉得有收获的可以点个赞点个关注哇 有问题也可以评论或找我交流 有评论必回复 目录 一 基础知识概念 关于控制流信息有如下几个基本概念 1 基本块 2 控制流图 cfg 3 有向图G 基于数据流分析的一些定义 1 到
  • SPDK/NVMe存储技术分析之SSD设备的发现(一)

    源代码及NVMe协议版本 SPDK spdk 17 07 1 DPDK dpdk 17 08 NVMe Spec 1 2 1 1 识别NVMe固态硬盘的方法 NVMe SSD是一个PCIe设备 那么怎么识别这种类型的设备 有两种方法 方法1
  • 工厂模式(分简单工厂模式、工厂方法模式、抽象工厂模式)

    1 工厂模式概述 1 1 简单工厂模式 简单工厂模式是一种创建型设计模式 它实现了创建对象的功能 但不使用任何具体类的名称 客户端通过调用工厂类的静态方法来创建一个具体的对象 无需关心对象创建的细节 1 2 工厂方法模式 工厂方法模式是一种