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

【设计模式】Head First 设计模式——工厂方法模式 C++实现

设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。

设计思想

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使得一个类的实例化延迟到子类。(目的:解耦,手段:虚函数)

动机

在软件系统中,经常面临着创建对象的工作;由于需求的变化,需要创建的对象的具体类型经常变化。

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

Factory Method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。

Factory Method模式通过面向对象的收发,将所要创建的具体对象工作延迟到子类,从而实现一种扩展(而非更改)的策略,较好地解决了这种耦合关系。

Factory Method 模式解决“单个对象”的需求变化。缺点在于创建方法、参数需要相同。

业务场景

在 MainForm 中需要对文件进行分解操作,但是分解的文件可能是二进制文件,文本文件,图片文件等等,这时候我们需要在 MainForm 创建对应的对象,然后调用分解函数。

一个非常直观的思路是:

class ISplitter {
public:virtual void split() = 0;virtual ~ISplitter() {}
};class BinarySplitter : public ISplitter {
//实现分解二进制文件
};class TxtSplitter : public ISplitter {
//实现分解TXT文件
};class PictureSplitter : public ISplitter {
//实现分解图片文件
};class VideoSplitter : public ISplitter {//实现分解视频文件   
};class MainForm : public Form {
public:void Button1_Click() {ISplitter* splitter = new BinarySplitter();  splitter->split();}
};

这是很自然的一种写法,问题的关键在于这一句代码:

ISplitter* splitter = new BinarySplitter();  

在等号的左边,是一个抽象类,属于抽象依赖(编译时依赖),但是等号的右边,是一个具体类,属于细节依赖。根据依赖倒置原则,抽象不应该依赖于细节,而这种写法很明显违背了这种原则。

下面看看使用工厂模式应该怎么去实现:

代码案例

编写专门的工厂类,再编写具体的工厂子类。在具体操作的 MainForm 中通过构造把子类对象传入。用多态的方式,避免了 MainForm 中的固定。

// 抽象类
class ISplitter {
public:virtual void split() = 0;virtual ~ISplitter() {}
};// 工厂基类
class SplitterFactory {
public:// 虚函数,延迟到运行时依赖virtual ISplitter* CreateSplitter() = 0;virtual ~SplitterFactory() {}
};//创建一个工厂类,专门负责对象的实例化// 具体类
class BinarySplitter : public ISplitter {};class TxtSplitter : public ISplitter {};class PictureSplitter : public ISplitter {};class VideoSplitter : public ISplitter {};// 具体工厂:每一个具体类都对应着一个专门生产这种对象的工厂
class BinarySplitterFactory : public SplitterFactory {
public:virtual ISplitter* CreateSplitter() {return new BinarySplitter();}
};class TxtSplitterFactory : public SplitterFactory {
public:virtual ISplitter* CreateSplitter() {return new TxtSplitter();}
};class PictureSplitterFactory : public SplitterFactory {
public:virtual ISplitter* CreateSplitter() {return new PictureSplitter();}
};class VideoSplitterFactory : public SplitterFactory {
public:virtual ISplitter* CreateSplitter() {return new VideoSplitter();}
};// MainForm 没有具体类的依赖
// 只有抽象的类的依赖
// 把依赖具体类转移了
class MainForm : public Form {SplitterFactory* factory;  // 含有工厂成员public:MainForm(SplitterFactory* factory) {this->factory = factory;}//想要实例化什么样的对象,由运行时决定void Button1_Click() {ISplitter* splitter = factory->CreateSplitter();  // 多态newsplitter->split();}
};

相关文章:

【设计模式】Head First 设计模式——工厂方法模式 C++实现

设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。 设计思想 定义一个用于创建对象的接口,让子…...

【爬虫】7.2. JavaScript动态渲染界面爬取-Selenium实战

JavaScript动态渲染界面爬取-Selenium实战 爬取的网页为:https://spa2.scrape.center,里面的内容都是通过Ajax渲染出来的,在分析xhr时候发现url里面有token参数,所有我们使用selenium自动化工具来爬取JavaScript渲染的界面。 fr…...

c语言实训心得3篇集合

c语言实训心得体会一: 在这个星期里,我们专业的学生在专业老师的带领下进行了c语言程序实践学习。在这之前,我们已经对c语言这门课程学习了一个学期,对其有了一定的了解,但是也仅仅是停留在了解的范围,对里…...

2023高教社杯数学建模B题思路代码 - 多波束测线问题

# 1 赛题 B 题 多波束测线问题 单波束测深是利用声波在水中的传播特性来测量水体深度的技术。声波在均匀介质中作匀 速直线传播, 在不同界面上产生反射, 利用这一原理,从测量船换能器垂直向海底发射声波信 号,并记录从声波发射到…...

MySql 变量

1.系统变量 1.1 系统变量分类 变量由系统定义,不是用户定义,属于 服务器 层面。系统变量分为全局系统变量(需要添加 global 关键字)以及会话系统变量(需要添加 session 关键字),有时也把全局系…...

2023-简单点-make和build都是什么东西?

make make命令根据makefile.txt中的命令进行批量处理。 编译时自动检查文件是否更新,如果文件已经更改,make会对他重新编译,否则跳过。 编译选定的目标,但是Make只编译上次编译变化过的文件,减少重复劳动&#xff0…...

Nginx 学习(八)Nginx实现用IP测试灰度发布

1.1 问题 配置Nginx使其可以将动态访问转交给uWSGI: 1.2 方案 安装Python工具及依赖 安装uWSGI并编写配置文件 1.3 步骤 实现此案例需要按照如下步骤进行。 步骤一: 1)安装python依赖软件[rootproxy python]# yum -y install gcc make pytho…...

QT 自定义信号

自定义信号,需要 1.在singnals:区域下写信号函数,以及函数对应的参数 2. 需要emit关键字进行发射信号 3. 在需要处理该信号的其他类中,建立信号和其信号槽函数connect() 4. 在其他类中创建信号处理槽函数 #include "mythread.h"my…...

注解方式配置SpringMVC

注解配置SpringMVC 1. 初始化类,代替web.xml2. 创建SpringConfig配置类,代替spring的配置文件3. 创建SpringMVCConfig配置类,代替SpringMVC.xml配置文件4. 项目结构 1. 初始化类,代替web.xml Spring3.2引入了一个便利的WebApplic…...

2023年限售股解禁研究报告

第一章 概述 解禁是指限售流通股过了限售承诺期,可以在二级市场自由买卖的过程。根据流通性质,可将上市公司股份分为有限售条件的流通股(“限售流通股”)及无限售条件的流通股(“流通股”)。 限售流通股指…...

『PyQt5-Qt Designer篇』| 08 Qt Designer中容器布局和绝对布局的使用

08 Qt Designer中容器布局和绝对布局的使用 1 容器布局1.1 设计容器布局1.2 保存文件并执行2 绝对布局2.1 设计绝对布局2.2 保存文件并执行1 容器布局 1.1 设计容器布局 先拖入一个容器Frame容器,然后拖入几个控件: 把拖入的控件拖入容器中: 选中容器,右键-布局-栅格布局:…...

Android 下第一个fragment app 先Java 后Kotlin

看着视频学习的,Fragment:3.Fragment使用方法_哔哩哔哩_bilibili 程序的运行效果是,手机页面有2个fragment,每个fragment 有一个text view,一个按钮,按一下显示,fine,and you?,各自…...

行业追踪,2023-09-04

自动复盘 2023-09-04 凡所有相,皆是虚妄。若见诸相非相,即见如来。 k 线图是最好的老师,每天持续发布板块的rps排名,追踪板块,板块来开仓,板块去清仓,丢弃自以为是的想法,板块去留让…...

Android MQTT:实现设备信息上报与远程控制

Android MQTT:实现设备信息上报与远程控制 1. 介绍 1.1 MQTT是什么? MQTT(Message Queuing Telemetry Transport)是一种轻量级的消息传输协议,最初由IBM开发,用于连接远程设备与服务器之间的通信。它在物…...

Python爬虫——新手使用代理ip详细教程

Python代理IP爬虫是一种可以让爬虫拥有更多网络访问权限的技术。代理IP的作用是可以为爬虫提供多个IP地址,从而加快其爬取数据的速度,同时也可以避免因为访问频率过高而被网站封禁的问题。本文将介绍如何使用Python实现代理IP的爬取和使用。 一、代理IP的…...

idea VCS配置多个远程仓库

Idea VCS配置多个远程仓库 首先要有连个远程仓库地址 idea 添加数据源 查看推送记录 添加数据源 ok之后填写账号密码 推送本地项目 选择不同远程地址 push 查看不同远程地址的 不同分支的 推送记录 不期而遇的温柔: 应用开源架构进行项目开发,特别是那…...

LKPNR: LLM and KG for Personalized News Recommendation Framework

本文是LLM系列文章,针对《LKPNR: LLM and KG for Personalized News Recommendation Framework》的翻译。 LKPNR:LLM和KG的个性化新闻推荐框架 摘要1 引言2 相关工作3 问题定义4 框架5 实验6 案例7 结论 摘要 准确地向用户推荐候选新闻文章是个性化新闻推荐系统面…...

Xshell只能打开一个会话、左边栏消失不见、高级设置在哪儿、快捷键设置解决

Xshell只能打开一个会话、左边会话栏消失不见、高级设置在哪儿解决 1.问题: xshell会话(窗口)上方切换栏不见了的处理办法 解决方法:ctrl shift t 2.问题: 左边会话管理器不见了 解决方法: 3.问题…...

Android Retrofit 高级使用与原理

简介 在 Android 开发中,网络请求是一个极为关键的部分。Retrofit 作为一个强大的网络请求库,能够简化开发流程,提供高效的网络请求能力。本文将深入介绍 Retrofit 的高级使用与原理,帮助读者更全面地理解和应用这一库。 什么是…...

Unity3D开发流程及注意事项

使用Unity3D开发游戏需要遵循一定的流程和注意事项,以确保项目的顺利进行并获得良好的结果。以下是一般的游戏开发流程以及一些注意事项,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。 游…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?

一、核心优势&#xff1a;专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发&#xff0c;是一款收费低廉但功能全面的Windows NAS工具&#xff0c;主打“无学习成本部署” 。与其他NAS软件相比&#xff0c;其优势在于&#xff1a; 无需硬件改造&#xff1a;将任意W…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具

文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...