C++工厂方法模式:Factory Method Pattern

2023-10-28

工厂(Factory)处理创建对象的细节,只负责创建对象。方便不同的对象需要时通过工厂来获取对象。

简单工厂其实不是一种设计模式,反而比较像是一种编程习惯。但是由于经常被使用,有些开发人员把这个编程习惯误认为是“工厂模式”。

简单工厂模式:实例化对象的时候不再使用 new Object()的形式,根据用户选择的产品类名或者某个标识来实例化具体的类。但是会业务扩展而使得简单工厂类数量庞大。

工厂方法模式:工厂方法模式是对简单工厂模式进一步的解耦,在工厂方法模式中是一类产品对应一个工厂类,而这些工厂类都继承于一个抽象工厂。这相当于是把原本会随着业务扩展而数量庞大的简单工厂类,分类成了一个个的具体产品工厂类,这样代码就不会都耦合在同一个类里。

工厂方法模式定义了一个创建对象的接口,但由子类决定要具体实现化的类是哪一个。工厂方法让类把实例化推迟到子类。

假设现在我们准备开一家披萨店,不同种类的披萨都有相同的一套制作流程:被准备、被烘烤、被切片、被装盒,但是不同的披萨有不同的口味和添加不同的配料比如cheese、veggie等。随着业务的扩展,来自不同地方的风味各异的披萨店准备来加盟,它们有不同的风味但是需要添加的配料还是相同。(后续扩展:实现一个原料工厂生产不同的原料:抽象工厂模式)

设计原则

依赖倒置原则:披萨店最开始的设计是一家披萨店直接生产各个具体的披萨类,这样导致披萨店(高层组件)过分依赖各个具体的披萨类(低层组件)。解决方法是抽象出一个Pizza类,让高层组件和低层组件都依赖于这个抽象类。

类图:

把变化和不变化的部分分离,把可能变化的具体披萨类的生产封装在一个工厂中。

由于Pizza对象是抽象的,orderPizza()并不知道哪些具体类参与进来了,换句话说,这就是解耦(decouple)。

加盟店有它的好处,可以从PizzaStore继承获得所有的功能。加盟店只需要继承PizzaStore,然后提供createPizza()方法实现自己的披萨风味即可。注意,超类的orderPizza()方法并不知道创建的披萨是哪一种,它只知道这个披萨可以被准备、被烘烤、被切片、被装盒。

缺点

当需要新增产品时,都必须要编写新的具体产品类,而且还要提供与之对应的具体工厂类,随着类的不断增加,在一定程度上增加了系统的复杂度,会有更多的类需要编译和加载,会给系统带来一些额外的开销。

实现如下:

pizzaStore.h:

#ifndef PIZZASTORE_H
#define PIZZASTORE_H
#include "pizza.h"

class PizzaStore {
public:
    virtual Pizza* orderPizza(string type) = 0;
    virtual Pizza* createPizza(string type) =  0;
};

#endif // PIZZASTORE_H

NYPizzaStore.h:

#ifndef NYPIZZASTORE_H
#define NYPIZZASTORE_H
#include "pizzaStore.h"
#include "NYStyleCheesePizza.h"

class NYPizzaStore : public PizzaStore {
public:
    virtual Pizza* orderPizza(string type) override;
    virtual Pizza* createPizza(string type) override;
};

Pizza* NYPizzaStore::createPizza(string type)
{
    Pizza* pizza;

    if(type == "cheese")
    {
        pizza = new NYStyleCheesePizza();
    }

    return pizza;
}

Pizza* NYPizzaStore::orderPizza(string type)
{
    Pizza* pizza;
    pizza = createPizza(type);
    pizza->prepare();
    pizza->bake();
    pizza->cut();
    pizza->box();

    return pizza;
}

#endif // NYPIZZASTORE_H

ChicagoPizzaStore.h:

#ifndef CHICAGOPIZZASTORE_H
#define CHICAGOPIZZASTORE_H
#include "pizzaStore.h"
#include "ChicagoStyleVeggiePizza.h"

class ChicagoPizzaStore : public PizzaStore {
public:
    virtual Pizza* orderPizza(string type) override;
    virtual Pizza* createPizza(string type) override;
};

Pizza* ChicagoPizzaStore::createPizza(string type)
{
    Pizza* pizza;

    if(type == "veggie")
    {
        pizza = new ChicagoStyleVeggiePizza();
    }

    return pizza;
}

Pizza* ChicagoPizzaStore::orderPizza(string type)
{
    Pizza* pizza;
    pizza = createPizza(type);
    pizza->prepare();
    pizza->bake();
    pizza->cut();
    pizza->box();

    return pizza;
}
#endif // CHICAGOPIZZASTORE_H

pizza.h:

#ifndef PIZZA_H
#define PIZZA_H
#include <iostream>
#include <string>
using namespace std;

class Pizza {
public:
    void prepare();
    void bake();
    void cut();
    void box();
    void display();

protected:
    string m_type;
};

void Pizza::prepare()
{
    cout << "准备,";
}

void Pizza::bake()
{
    cout << "烘烤,";
}

void Pizza::cut()
{
    cout << "切片,";
}

void Pizza::box()
{
    cout << "装箱,";
}

void Pizza::display()
{
    cout << m_type << "制作好了!" << endl;
}
#endif // PIZZA_H

NYStyleCheesePizza.h:

#ifndef NYSTYLECHEESEPIZZA_H
#define NYSTYLECHEESEPIZZA_H
#include "pizza.h"

class NYStyleCheesePizza : public Pizza {
public:
    NYStyleCheesePizza();
};

NYStyleCheesePizza::NYStyleCheesePizza()
{
    m_type = "纽约奶酪披萨";
}

#endif // NYSTYLECHEESEPIZZA_H


ChicagoStyleVeggiePizza.h:

#ifndef CHICAGOSTYLEVEGGIEPIZZA_H
#define CHICAGOSTYLEVEGGIEPIZZA_H
#include "pizza.h"

class ChicagoStyleVeggiePizza : public Pizza {
public:
    ChicagoStyleVeggiePizza();
};

ChicagoStyleVeggiePizza::ChicagoStyleVeggiePizza()
{
    m_type = "芝加哥蔬菜披萨";
}

#endif // CHICAGOSTYLEVEGGIEPIZZA_H

main.cpp:

/*
 * 工厂方法模式
 *
 * date:2023-9-8
*/

#include "NYPizzaStore.h"
#include "ChicagoPizzaStore.h"

int main()
{
    cout << "订购一个纽约风味的奶酪披萨" << endl;
    PizzaStore *pizzaStore = new NYPizzaStore();
    Pizza *pizza = pizzaStore->orderPizza("cheese");
    pizza->display();

    cout << "\n芝加哥风味的披萨店加盟,可以订购芝加哥风味的披萨了\n" << endl;

    cout << "订购一个芝加哥风味的蔬菜披萨" << endl;
    pizzaStore = new ChicagoPizzaStore();
    pizza = pizzaStore->orderPizza("veggie");
    pizza->display();
}

运行结果:

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

C++工厂方法模式:Factory Method Pattern 的相关文章

  • 【设计模式】工厂方法模式(C#)

    设计模式 工厂方法模式 1 概述 针对简单工厂中的缺点 使用工厂方法模式就可以完美的解决 完全遵循开闭原则 定义一个用于创建对象的接口 让子类决定实例化哪个产品类对象 工厂方法使一个产品类的实例化延迟到其工厂的子类 工厂方法模式的主要角色
  • C++复合模式:Compound Pattern

    模式通常被一起使用 并被组合在同一个设计解决方案中 复合模式在一个解决方案中结合两个或多个模式 以解决一般或重复发生的问题 注 是为了解决一般或重复发生的问题 而不是简单的认为使用了多个模式就是复合模式 绝不要为了使用模式而使用模式 具体问
  • C++外观模式:Facade Pattern

    装饰者 不改变接口 但加入责任 适配器 将一个接口转换成另一个接口 外观 让接口更简单 外观模式 将一个或数个类的复杂的一切都隐藏在背后 只显露出一个干净美好的外观 外观模式提供了一个统一的接口 用来访问子系统中的一群接口 外观模式定义了一
  • C++解释器模式:Interpreter Pattern

    当有语言要解释时 请使用解释器模式为语言创建解释器 解释器模式的核心是解释器类 在解释器模式中一般会定义两种解释器 终结符解释器 Terminal Expression Interpreter 终结符解释器用于解释语言中的基本单位 对应语法
  • C++工厂方法模式:Factory Method Pattern

    工厂 Factory 处理创建对象的细节 只负责创建对象 方便不同的对象需要时通过工厂来获取对象 简单工厂其实不是一种设计模式 反而比较像是一种编程习惯 但是由于经常被使用 有些开发人员把这个编程习惯误认为是 工厂模式 简单工厂模式 实例化
  • C++状态模式:State Pattern

    状态模式 允许对象在其内部状态改变时改变它的行为 对象看起来好像修改类它的类 状态模式是有限状态机 Finite State Machine 的一种实现方式 我们都知道 http请求报文由请求行 请求头 请求空行和请求体四部分组成 服务器在
  • [大话设计模式C++版] 第8章 雷锋依然在人间 —— 工厂方法模式

    源码可以在这里找到 大话设计模式C 版 模拟大学生学雷锋 main cpp class LeiFeng public void Sweep cout lt lt 扫地 lt lt endl void Wash cout lt lt 洗衣 l
  • 设计模式(四)单例和简单工厂的融合

    前面三篇文章介绍了三种模式 单例 简单工厂和工厂方法 其中 简单工厂和工厂方法都是基于同一个实际问题 但是 这个例子里有几个问题 1 职工的创建在main函数中 不合理 可能多个函数都会需要访问职工信息 2 职工是程序直接创建的 不合理 一
  • 工厂模式(分简单工厂模式、工厂方法模式、抽象工厂模式)

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

    工厂方法模式 根据简单工厂模式的案例可知 如果我们想要添加一种立方运算 只需要创建一个立方运算类继承运算类 然后在工厂类中添加一个case分支用于逻辑判断 问题在于 我们在进行功能扩展的同时 也修改了工厂类中的代码 这很明显违背了开放 封闭
  • 设计模式精讲-工厂方法模式

    设计模式精讲 工厂方法模式 模式定义 实战说明 简单工厂实现 不是设计模式 工厂方法 应用场景 主要优点 源码中的应用 模式定义 定义一个用于创建对象的接口 让子类决定实例化哪一个类 Factory Method 使得一个类的实例化延迟到子
  • 设计模式-工厂方法模式

    文章目录 前言 工厂方法模式概述 使用场景 工厂方法模式优缺点 Java代码示例 前言 当我们面临需要创建不同类型对象的需求时 通常会使用工厂方法模式 工厂方法模式是一种创建型设计模式 它提供了一种将对象的创建与使用分离的方法 允许我们在不
  • C++桥接模式:Bridge Pattern

    在现实生活中 某些类具有两个或多个维度的变化且这多个维度都可能需要后期扩展 如图形既可按形状分 又可按颜色分 如何设计类似于 Photoshop 这样的软件 能画不同形状和不同颜色的图形呢 如果用继承方式 m 种形状和 n 种颜色的图形就有
  • 设计模式(三)工厂方法模式

    前一篇文章介绍了简单工厂模式 留下了一个疑问 如果需要扩展员工等级 有没有不修改既有接口的方式 答案就是工厂方法模式 既然员工的职级可以扩展 那创建对应职级员工的工厂是不是也可以扩展 工厂基类提供一个接口获取具体的产品 一旦有新的产品 就创
  • java设计模式——工厂方法模式(Factory Method Pattern)

    简单工厂模式虽然简单 但也受到很大限制 扩展性太差 当系统中需要引入新产品时 由于静态工厂方法通过所传入参数的不同来创建不同的产品 这必定要修改工厂类的源代码 将违背 开闭原则 如何实现增加新产品而不影响已有代码 工厂方法模式应运而生 本文
  • 简单工厂模式(静态工厂方法模式)

    概述 简单工厂模式专门定义一个类来负责创建其他类的实例 被创建的实例通常都具有共同的父类 不是23种模式中的一种 是一种编码习惯 优点 1 工厂类含有必要的判断逻辑 可以决定在什么时候创建哪一个产品类的实例 客户端可以免除直接创建产品对象的
  • C++命令模式:Command Pattern

    把方法调用封装起来 调用此方法的对象不需要关心方法是怎么运行的 还可以重复使用这些封装来实现撤销 undo 案例 设计一个遥控器来控制不同类型的装置 比如热水器 空调 每个装置的具体步骤方法不一样 命令模式可以将 动作的请求者 从 动作的执
  • C++责任链模式:Chain of Responsibility Pattern

    当你想要让一个以上的对象有机会能够处理某个请求的时候 就可以使用责任链模式 责任链模式 将请求的发送和接收解耦 让多个接收对象都有机会处理这个请求 将这些接收对象串成一条链 并沿着这条链传递这个请求 直到链上的某个接收对象能够处理它为止 通
  • Gof23设计模式之工厂方法模式和抽象工厂模式

    在java中 万物皆对象 这些对象都需要创建 如果创建的时候直接new该对象 就会对该对象耦合严重 假如我们要更换对象 所有new对象的地方都需要修改一遍 这显然违背了软件设计的开闭原则 如果我们使用工厂来生产对象 我们就只和工厂打交道就可
  • C++抽象工厂模式:Abstract Factory Pattern

    抽象工厂模式是工厂方法模式的升级版本 工厂方法模式只有一个抽象产品类 而抽象工厂模式有多个 工厂方法模式的具体工厂类只能创建一个具体产品类的实例 而抽象工厂模式可以创建多个 案例 在上一章节工厂方法模式的基础上 将披萨的各种原料生产抽象成一

随机推荐

  • JavaScript设置innerHTML时出现“未知的运行时错误”--我也遇上了

    在Ajax里经常会通过innerHTML来改变界面 这个比使用DOM要简单一些 比如 element innerHTML something 不过 在IE中 有时候会出现 未知的运行时错误 unknown runtime error 而在f
  • C语言在读取txt类型文件中的汉字字符串出现乱码的解决办法

    题目 C语言在读取txt类型文件中的汉字字符串出现乱码的解决办法 以下是本篇文章正文内容 欢迎朋友们进行指正 一起探讨 共同进步 来自考研路上的lwj 一 前言 当我们在练习文件这一章节时 因为需要从文件中读取数据 有很多数据是中文形式的
  • 【 Spring Boot + MyBatis Plus + Druid】

    1 1 配置版本 具体使用到的各配置版本信息如下 JAVA17 SpringBoot 3 0 5 MyBatis Plus 3 5 3 1 Druid 1 1 14 MySql 5 0 8 因为以前装的老版本的mysql 用的mysql c
  • K210、Openmv与串行总线舵机通信(基于micropython)舵机驱动板和舵机控制板代码

    最近博主在使用幻尔公司 串行总线舵机时 想使用k210控制 openmv和k210都是micropython编写的所以这个代码是通用的 由于官方没有相关例程 树莓派的版本是python版本代码 用不了 特此分享一下控制代码 主要调用函数 a
  • Spring的应用上下文

    Spring提供了多个应用上下文 以下三个必须掌握 因为最容易遇到 1 ClassPathXmlApplicationContext 从classpath处获取xml文件来加载一个上下文 2 ClassPathXmlApplicationC
  • Java学生管理系统(简单版)

    步骤 A 定义学生类 B 学生管理系统的主界面的代码编写 C 学生管理系统的查看所有学生的代码编写 D 学生管理系统的添加学生的代码编写 E 学生管理系统的删除学生的代码编写 F 学生管理系统的修改学生的代码编写 A 定义学生类 Stude
  • HTML表格标签

    标签 与 标签的关系 是互相包裹的关系 或者说 里外嵌套的关系 快捷写法 p gt img 表格 由 table 标签来定义 每个表格均有若干行 由 tr 标签定义 每行被分割为若干单元格 由 td 标签定义 字母 td 指表格数据 tab
  • PHP实现AES-128-CBC加密+base64_encode

    AES加密 public function encrypt input 传false相当于base64 encode 编码了一次 encode base64 encode openssl encrypt input AES 128 CBC
  • SSH反向代理使用

    SSH反向代理 先说说什么是代理 源服务器由于各种原因无法访问目标服务器提供的服务 但是存在一个agent服务器 源服务器可以访问它 它可以访问目标服务器 那么源服务器的消息发给他 它在把请求转发给目标服务器 就间接的实现了源服务器访问目标
  • 进程(process)、线程(thread)、协程 (Coroutine) 的区别

    说到协程 Coroutine 我们必须提到两个名称相似的东西 在操作系统 os 级别 有进程 process 和线程 thread 两个 仅从我们常见的讲 实际的 东西 不说概念是因为这两个家伙的确不仅仅是概念 而是实际存在的 os的代码管
  • Short与Integer互转

    int 是4字节 short 是2字节的 如果将int Integer 转成short Short 那么必须强制转换 否则会报编译异常 但是 当int Integer 是一个final时 可以直接转换 不必强转 如 short t 1 正确
  • 【力扣1462】课程表(拓扑排序+bitset优化到O(n))

    题目描述 你总共需要上 numCourses 门课 课程编号依次为 0 到 numCourses 1 你会得到一个数组 prerequisite 其中 prerequisites i ai bi 表示如果你想选 bi 课程 你 必须 先选
  • android虚拟机启动不了,android虚拟机adb不能启动情况汇总

    在开启android虚拟机的时候 可能会遇到adb不能启动的问题 大概有以下几下情况 1 报错 BUILD FAILED D workspace ganji build xml 144 The following error occurre
  • 底量超顶量超级大黑马指标源码_底量超顶量超级大黑马指标源码

    主力买力度 LARGEINTRDVOL 100 VOL COLORRED 主力卖力度 LARGEOUTTRDVOL 100 VOL COLORGREEN 超B L2 VOL 0 0 VOL CAPITAL 大B L2 VOL 1 0 VOL
  • linux服务器高并发的极限和瓶颈

    最大并发数探究 Fancylee 2022 03 30 并发数 QPS 并发数 系统中同时存在的请求 同时处理中 QPS query per second 每秒的访问数 如何理解 将整个系统比喻成一个超市 QPS在超市门口测得的每秒钟有多少
  • U盘重装系统后可能遇到的问题

    一 重装系统 具体流程安装参考百度盘的使用优启通进行安装 安装完系统后可能会出现如下现象 一般台式机比笔记本简单 因为台式机不存在外围设备 例如触控板等 1 自己的优启通的万能驱动可能不具有相应的硬件驱动 在安装完系统后会提示 未找到相应的
  • 使用Hyperledger Composer将业务网络部署到单个组织的Hyperledger Fabric区块链上

    转载请标明出处 http blog csdn net qq 27818541 article details 78727076 本文出自 BigManing的博客 前言 先前准备 1先满足下列环境要求 2安装Hyperledger Comp
  • 让你的代码变的更加健壮(Making your C++ code robust)

    Making your C code robust Introduction 在实际的项目中 当项目的代码量不断增加的时候 你会发现越来越难管理和跟踪其各个组件 如其不善 很容易就引入BUG 因此 我们应该掌握一些能让我们程序更加健壮的方法
  • Unity AVPro Video使用和WebGL播放视频流

    1 创建Media Player对象 在Hierarchy视图右击 Video gt Media Player 或者选择菜单栏的GameObject菜单 然后选择 Video gt Media Player 2 创建Display uGui
  • C++工厂方法模式:Factory Method Pattern

    工厂 Factory 处理创建对象的细节 只负责创建对象 方便不同的对象需要时通过工厂来获取对象 简单工厂其实不是一种设计模式 反而比较像是一种编程习惯 但是由于经常被使用 有些开发人员把这个编程习惯误认为是 工厂模式 简单工厂模式 实例化