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

C++设计模式(工厂模式)

一、介绍

1.动机

在软件系统中,经常面临着创建对象的工作,这些对象有可能是一系列相互依赖的对象;由于需求的变化,需要创建的对象的具体类型经常变化,同时也可能会有更多系列的对象需要被创建。

如何应对这种变化?如何绕过常规的对象创建方法(new),提供一种“封装机制”来避免客户程序和这种“具体对象创建工作”的紧耦合?

 

2.定义

工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。——GOF

抽象工厂模式:提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定它们具体的类。——GOF

 

3.结构图

工厂方法模式:

42ffb07cfb8048cea5e8a821a0043e38.jpeg

抽象工厂模式:

ff1b2684237c4725ac531ae5b3535925.jpeg

 

4.要点总结

工厂方法模式:

  • Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系(new)会导致软件的脆弱。
  • Factory Method模式通过面向对象的手法,将创建具体对象的工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种紧耦合关系。
  • Factory Method模式解决“单个对象”的需求变化,缺点在于要求创建方法/参数相同。

抽象工厂模式:

  • 如果没有应对“多系列对象构建”的需求变化,则没有必要使用Abstract Factory模式,这时候使用简单的工厂完全可以。
  • “系列对象”指的是在某一特定系列下的对象之间有相互依赖或相互作用的关系,不同系列的对象之间不能相互依赖。
  • Abstract Factory模式主要在于应对“新系列”的需求变动,其缺点在于难以应对“新对象”的需求变动。

 

 

二、工厂模式

1.概念

工厂模式避免直接使用new运算符来创建产品对象,它提供一个抽象的工厂接口来创建和管理对象的实例化,同时也支持对创建逻辑的封装和扩展。

①工厂模式的优点:

  • 解耦:客户端代码与具体产品的创建逻辑分离,只依赖于抽象产品和工厂接口。
  • 扩展性:增加新产品时只需添加新的具体产品类和相应的具体工厂类,不需要修改现有代码。
  • 重用性:同一个工厂类可以用来创建多个产品,提高代码的复用率。

②工厂模式的缺点:

  • 增加类的数量:可能导致系统中类的数量增加,尤其是在使用抽象工厂模式时。
  • 复杂性:引入额外的抽象层,可能会增加理解和维护的复杂性。

 

2.实现要点

  • 抽象产品:定义一个抽象产品类,它将作为具体产品的共同基类或接口。
  • 具体产品:为每个具体的产品实现一个类,这些类将继承或实现抽象产品类。
  • 抽象工厂:创建一个抽象工厂类,它将提供创建产品的接口。
  • 具体工厂:实现抽象工厂中定义的方法,创建具体的产品对象。
  • 客户端:使用工厂方法来创建对象,但不需要知道具体产品的类。

工厂模式可以分为三种类型:简单工厂模式、工厂方法模式及抽象工厂模式。

 

3.简单工厂模式

通过一个工厂类来创建不同类型的产品实例,根据传递的参数来决定创建哪种具体的产品。

//文具类(抽象产品)
class Stationery {
public:virtual void use() = 0;virtual ~Stationery() {}
};//钢笔类(具体产品)
class Pen :public Stationery {
public:Pen() {cout << "Pen()" << endl;}virtual ~Pen() {cout << "~Pen()" << endl;}virtual void use() override{cout << "Use pen." << endl;}
};//铅笔类(具体产品)
class Pencil :public Stationery {
public:Pencil() {cout << "Pencil()" << endl;}virtual ~Pencil() {cout << "~Pencil()" << endl;}virtual void use() override {cout << "Use pencil." << endl;}
};//枚举类型
enum StationeryType {PEN,PENCIL
};//文具工厂类
class StationeryFactory {
public:static shared_ptr<Stationery> createStationery(StationeryType type) {switch (type) {case PENCIL:return shared_ptr<Stationery>(new Pencil);break;case PEN:return shared_ptr<Stationery>(new Pen);break;defalut:return nullptr;break;}}
};

 测试代码:

shared_ptr<Stationery> pen = StationeryFactory::createStationery(PEN);
pen->use();
shared_ptr<Stationery> pencil = StationeryFactory::createStationery(PENCIL);
pencil->use();

 输出结果;

Pen()
Use pen.
Pencil()
Use pencil.
~Pencil()
~Pen()

 

4.工厂方法模式

将创建具体产品的任务分发给具体的产品工厂,每个具体工厂负责创建对应的具体产品对象。

//交通工具类(抽象类)
class Vehicle {
public:virtual void run() = 0;virtual ~Vehicle() {}
};//汽车类(具体类)
class Car :public Vehicle {
public:virtual void run() override {cout << "The car is running." << endl;}
};//自行车类(具体类)
class Bicycle :public Vehicle {
public:virtual void run() override {cout << "The bicycle is moving." << endl;}
};//交通工具工厂(抽象工厂)
class VehicleFactory {
public:virtual Vehicle* createVehicle() = 0;virtual ~VehicleFactory() {}
};//汽车工厂(具体工厂)
class CarFactory :public VehicleFactory {
public:virtual Vehicle* createVehicle() override {return new Car();}
};//自行车工厂(具体工厂)
class BicycleFactory :public VehicleFactory {
public:virtual Vehicle* createVehicle() override {return new Bicycle();}
};

测试代码: 

VehicleFactory* carFactory = new CarFactory();
Vehicle* car = carFactory->createVehicle();
car->run();
delete car;
delete carFactory;VehicleFactory* bicycleFactory = new BicycleFactory();
Vehicle* bicycle = bicycleFactory->createVehicle();
bicycle->run();
delete bicycle;
delete bicycleFactory;

输出结果: 

The car is running.
The bicycle is moving.

 

5.抽象工厂模式

提供一个抽象的工厂接口以及多个具体工厂类,每个具体工厂类负责创建一种或多种产品。

//桌子类(抽象类)
class Table {
public:virtual void display() = 0;virtual ~Table() {}
};//现代风格桌子(具体类)
class ModernTable :public Table {
public:virtual void display() override {cout << "A modern style table." << endl;}
};//古典风格桌子(具体类)
class ClassicalTable :public Table {
public:virtual void display() override {cout << "A classical style table." << endl;}
};//椅子类(抽象类)
class Chair {
public:virtual void sit() = 0;virtual ~Chair() {}
};//现代风格椅子(具体类)
class ModernChair :public Chair {
public:virtual void sit() override {cout << "Sitting on modern style chair." << endl;}
};//古典风格椅子(具体类)
class ClassicalChair :public Chair {
public:virtual void sit() override {cout << "Sitting on classical style chair." << endl;}
};//沙发类(抽象类)
class Sofa {
public:virtual void relax() = 0;virtual ~Sofa() {}
};//现代风格沙发(具体类)
class ModernSofa :public Sofa {
public:virtual void relax() override {cout << "Relaxing on modern style sofa." << endl;}
};//古典风格沙发(具体类)
class ClassicalSofa :public Sofa {
public:virtual void relax() override {cout << "Relaxing on Classical style sofa." << endl;}
};//家具工厂(抽象工厂)
class FurnitureFactory {
public:virtual Table* createTable() = 0;virtual Chair* createChair() = 0;virtual Sofa* createSofa() = 0;virtual ~FurnitureFactory() {}
};//现代风格家具工厂(具体工厂)
class ModernFurnitureFactory :public FurnitureFactory {
public:virtual Table* createTable() override {return new ModernTable;}virtual Chair* createChair() override {return new ModernChair;}virtual Sofa* createSofa() override {return new ModernSofa;}
};//古典风格家具工厂(具体工厂)
class ClassicalFurnitureFactory :public FurnitureFactory {
public:virtual Table* createTable() override {return new ClassicalTable;}virtual Chair* createChair() override {return new ClassicalChair;}virtual Sofa* createSofa() override {return new ClassicalSofa;}
};

测试代码: 

FurnitureFactory* modernFactory = new ModernFurnitureFactory();
Table* modernTable = modernFactory->createTable();
Chair* modernChair = modernFactory->createChair();
Sofa* modernSofa = modernFactory->createSofa();
modernTable->display();
modernChair->sit();
modernSofa->relax();
delete modernTable;
delete modernChair;
delete modernSofa;FurnitureFactory* classicalFactory = new ClassicalFurnitureFactory();
Table* classicalTable = new ClassicalTable();
Chair* classicalChair = new ClassicalChair();
Sofa* classicalSofa = new ClassicalSofa();
classicalTable->display();
classicalChair->sit();
classicalSofa->relax();
delete classicalTable;
delete classicalChair;
delete classicalSofa;

 输出结果:

A modern style table.
Sitting on modern style chair.
Relaxing on modern style sofa.
A classical style table.
Sitting on classical style chair.
Relaxing on Classical style sofa.

 

 

 

相关文章:

C++设计模式(工厂模式)

一、介绍 1.动机 在软件系统中&#xff0c;经常面临着创建对象的工作&#xff0c;这些对象有可能是一系列相互依赖的对象&#xff1b;由于需求的变化&#xff0c;需要创建的对象的具体类型经常变化&#xff0c;同时也可能会有更多系列的对象需要被创建。 如何应对这种变化&a…...

多阶段报童问题动态规划求解,Python 实现

使用 python 编写了多阶段报童模型的动态规划算法。 使用了 python 的装饰器 dataclass &#xff0c;方便定义类尝试使用并行计算&#xff0c;没有成功&#xff0c;极易出错。动态规划中使用并行计算&#xff0c;还是挺有挑战的&#xff1b;而且并行计算不一定总是比非并行运算…...

【C++进阶篇】像传承家族宝藏一样理解C++继承

文章目录 须知 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助吗&#xff1…...

Java基础面试题09:Java异常处理完成以后,Exception对象会发生什么变化?

一、Java异常&#xff08;Exception&#xff09;基本概念 什么是异常&#xff1f; 简单来说&#xff0c;异常就是程序运行时发生了意外的“错误”或者“不正常现象”&#xff0c;导致程序中断。异常处理的目标是让程序在出现问题时能稳住&#xff0c;不会直接崩溃。 1.1 异常…...

mysql sql语句 between and 是否边界值

在 MySQL 中&#xff0c;使用 BETWEEN 运算符时&#xff0c;边界值是包括在内的。这意味着 BETWEEN A AND B 查询会返回 A 和 B 之间的所有值&#xff0c;包括 A 和 B 自身。 示例 假设有一个表 employees&#xff0c;其中有一个 salary 列&#xff0c;您可以使用以下查询&am…...

Java接收LocalDateTime、LocalDatee参数

文章目录 引言I java服务端的实现1.1 基于注解规范日期格式1.2 json序列化和反序列化全局配置自动处理日期格式化II 知识扩展: 枚举的转换和序列化III 签名注意事项引言 应用场景举例:根据时间段进行分页查询数据 前后端交互日期字符串统一是yyyy-MM-dd HH:mm:ss 或者yyyy-M…...

方差分析、相关分析、回归分析

第一章&#xff1a;方差分析 1.1 方差分析概述 作用: 找出关键影响因素&#xff0c;并进行对比分析&#xff0c;选择最佳组合方案。影响因素: 控制因素&#xff08;人为可控&#xff09;和随机因素&#xff08;人为难控&#xff09;。控制变量的不同水平: 控制变量的不同取值…...

SQLModel入门

SQLModel 系统性指南 目录 简介 什么是 SQLModel&#xff1f;为什么使用 SQLModel&#xff1f; 安装快速入门 定义模型创建数据库和表 基本 CRUD 操作 创建&#xff08;Create&#xff09;读取&#xff08;Read&#xff09;更新&#xff08;Update&#xff09;删除&#xff0…...

单片机蓝牙手机 APP

目录 一、引言 二、单片机连接蓝牙手机 APP 的方法 1. 所需工具 2. 具体步骤 三、单片机蓝牙手机 APP 的应用案例 1. STM32 蓝牙遥控小车 2. 手机 APP 控制 stm32 单片机待机与唤醒 3. 智能家居系统 4. 智能记忆汽车按摩座椅 四、单片机蓝牙手机 APP 的功能 1. 多种控…...

PostgreSQL在Linux环境下的常用命令总结

标题 登录PgSQL库表基本操作命令新建库表修改库表修改数据库名称&#xff1a;修改表名称修改表字段信息 删除库表pgsql删除正在使用的数据库 须知&#xff1a; 以下所有命令我都在Linux环境中执行验证过&#xff0c;大家放心食用&#xff0c;其中的实际名称换成自己的实际名称即…...

Unity shaderlab 实现LineSDF

实现效果&#xff1a; 实现代码&#xff1a; Shader "Custom/LineSDF" {Properties{}SubShader{Tags { "RenderType""Opaque" }Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{floa…...

Ubuntu中的apt update 和 apt upgrade

apt update 和 apt upgrade 是 Debian 及其衍生发行版&#xff08;如 Ubuntu&#xff09;中常用的两个 APT 包管理命令&#xff0c;它们各自执行不同的任务&#xff1a; apt update: 这个命令用于更新本地软件包列表。当你运行 apt update 时&#xff0c;APT 会从配置的源&…...

Android 中 Swipe、Scroll 和 Fling 的区别

Android 中 Swipe、Scroll 和 Fling 的区别 Swipe&#xff08;滑动&#xff09;Scroll&#xff08;滚动&#xff09;Fling&#xff08;甩动&#xff09;三者之间的区别代码示例 (Fling)总结 在 Android 应用中&#xff0c;Swipe、Scroll 和 Fling 都是用户在触摸屏幕上进行的滑…...

linux基础2

声明&#xff01; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&#…...

如何通过智能生成PPT,让演示文稿更高效、更精彩?

在快节奏的工作和生活中&#xff0c;我们总是追求更高效、更精准的解决方案。而在准备演示文稿时&#xff0c;PPT的制作往往成为许多人头疼的问题。如何让这项工作变得轻松且富有创意&#xff1f;答案或许就在于“AI生成PPT”这一智能工具的广泛应用。我们就来聊聊如何通过这些…...

执法记录仪数据自动备份光盘刻录归档系统

派美雅按需研发的执法记录仪数据自动备份光盘刻录归档系统&#xff0c;为用户提供数据自动上传到刻录服务端、数据上传后自动归类&#xff0c;全自动对刻录端视频文件大小进行实时监测&#xff0c;满盘触发刻录&#xff0c;无需人工干预。告别传统刻录存在的痛点&#xff0c;实…...

启动SpringBoot

前言&#xff1a;大家好我是小帅&#xff0c;今天我们来学习SpringBoot 文章目录 1. 环境准备2. Maven2.1 什么是Maven2.2 创建⼀个Maven项⽬2.3 依赖管理2.3.1 依赖配置2.3.2 依赖传递2.3.4 依赖排除2.3.5 Maven Help插件&#xff08;plugin&#xff09; 2.4 Maven 仓库2.6 中…...

重定向操作和不同脚本的互相调用

文章目录 前言重定向操作和不同脚本的互相调用 前言 声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 重定向操作和不同脚本的互相调用 1.不同脚本的互相…...

51单片机教程(九)- 数码管的动态显示

1、项目分析 通过演示数码管动态显示的操作过程。 2、技术准备 1、 数码管动态显示 4个1位数码管和单片机如何连接 a、静态显示的连接方式 优点&#xff1a;不需要动态刷新&#xff1b;缺点&#xff1a;占用IO口线多。 b、动态显示的连接方式 连接&#xff1a;所有位数码…...

golang支持线程安全和自动过期map

在 Golang 中&#xff0c;原生的 map 类型并不支持并发安全&#xff0c;也没有内置的键过期机制。不过&#xff0c;有一些社区提供的库和方案可以满足这两个需求&#xff1a;线程安全和键过期。 1. 使用 sync.Map&#xff08;线程安全&#xff0c;但不支持过期&#xff09; Go…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

C# 表达式和运算符(求值顺序)

求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如&#xff0c;已知表达式3*52&#xff0c;依照子表达式的求值顺序&#xff0c;有两种可能的结果&#xff0c;如图9-3所示。 如果乘法先执行&#xff0c;结果是17。如果5…...