软件设计模式 --- 类,对象和工厂模式的引入
Q1:什么是软件设计模式?
A:软件设计模式,又称设计模式。它是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。综上:设计模式就是泛指一系列编程的思想,是代码设计经验的总结,基于设计模式来开发代码可以使得程序更加稳定,拓展性更强。
Q2:为什么要学习设计模式?
A:在以往的项目开发中,不管是 ftp服务器 还是 图像识别智能垃圾桶 又或者更之前的智能小车项目,都没有一个固定的代码开发格式,更多的是根据需求一个个实现功能,虽然有了分文件编程的思想,但是代码整体还是缺乏规整度。尤其是在开发过程中,一个功能的实现经常会导致其他功能出现问题,所以需要学习设计模式,使得代码更加健壮和格式化。
Q3:算法 VS 设计模式?
A: 注意,算法不是设计模式,因为算法是使用逻辑来解决某些特定的问题,其致力于解决问题而非设计问题
设计模式的分类
软件设计模式共有23种,总体来说可以被分为三大类:
- 五种创建型模式:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
- 七种结构型模式:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
- 十一种行为型模式:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式
而我接下来着重学习的是创建型模式中的“工厂(方法)模式”
类 & 对象
设计模式通常描述了一组相互紧密作用的类与对象:
小插曲:
类和对象其实在java中是一个更常见的概念(这也是为什么java被称为“面向对象”的语言),但是“类和对象”在设计模式中也被提到。值得注意的是,设计模式可以使用C语言来实现,所以C语言也可以实现”面向对象“的编程,但是相比java来说可能没那么直接,所以C语言还是被笼统的称为“面向过程”的语言,这不代表C语言就完全无法“面向对象”。
- 类:是一种用户自定义的引用数据类型,也称类类型 --> C语言的结构体的定义
struct student{int age;float score; //成员属性void (*s_slogan)(); //成员方法
};
- 对象:类的一种具象 --> C语言结构体类型的变量
struct student MJM;
struct student MMJ; //MJM,MMJ就是对象
结构体对象定义的补充
C语言的结构体, 共用体(联合体)_一个结构体里有两个共用体-CSDN博客
在以前学习结构体的博文中,介绍了几种常见结构体对象的定义方法:
现在,假设有一个结构体:
struct student{int age;float score; //成员属性void (*s_slogan)(); //成员方法
};
而我现在想要定义一个名为“stu1”的该结构体对象,并且我只想对其的“score”和“s_slogan”赋值而不管其他两个成员,那么就可以使用如下的定义方法:
struct student stu1 = {.score = 67.5, //注意,是逗号.s_slogan = stu1_slogan, //最后一项的逗号可加可不加
};
oop_test.c:
#include <stdio.h>struct student{int age;float score; //成员属性void (*s_slogan)(); //成员方法
};void stu1_slogan()
{printf("stu1: I will be no.1!\n");
}void stu2_slogan()
{printf("stu2: I want to make my parent proud!\n");
}int main(){struct student stu1 = {.score = 97.5,.s_slogan = stu1_slogan, //函数名等于其地址,所以此处是地址的赋值};struct student stu2 = {.score = 87,.s_slogan = stu2_slogan,};printf("score of stu1:%f\n",stu1.score);stu1.s_slogan();printf("score of stu2:%f\n",stu2.score);stu2.s_slogan();return 0;
}
实现效果:
工厂模式
工厂模式(Factory Pattern)是Java中最常见的设计模式之一,也可以使用C来实现。刚刚就提到过,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方法。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
使用SourceInsight编写代码
之前学习的使用SourceInsight查看源码的博文:
香橙派配合IIC驱动OLED & 使用SourceInsight解读源码_香橙派5 驱动屏幕-CSDN博客
学到现在,其实已经接触过多种编写代码的方式:
- 使用windows的Notepad++来编写:界面简单,但是缺乏和linux的交互
- 使用linux的vi来编写:最简单的一种,适合linux开发,但是vi界面并不友好
- 使用VS Code远程连接linux编程:界面友好,适合linux开发,但是对单片机内存占用较大
现在,尝试使用SourceInsight来编写代码!
- 使用SourceInsight来编写:适合多文件编程,界面友好,且编写完成后可以方便的查看跳转,但是缺乏和linux的交互
工厂模式的代码涉及大量 分文件编程 的思路,故可以使用SourceInsight来编写代码。但也如上所说,SourceInsight缺乏和linux的交互,所以在代码编写完成后需要发送到单片机进行编译和运行。
但是,这不代表必须要使用SourceInsight来编写分文件编程的代码,任何能编写C语言的工具理论上都可以使用,我也完全可以使用以前使用的任何一种方法来编写代码,只不过现在作为学习阶段目的是多接触一些不同的方式;并且SourceInsight也适合进行多文件的编程,仅此而已。
在windows下新建一个“factory_test”文件夹用于保存测试代码:
然后创建一个在“factory_test”下创建一个“stu1.c”:
然后打开SourceInsight,先点击左上方 Project -> Close Project来关闭之前打开的项目;
然后点击左上方 File -> Open -> 选择要编写的代码,此处选择stu1.c:
然后,就可以开始编写代码了,同样的步骤,可以使用SourceInsight打开stu2.c; stu3.c; stu.h; main.c:
(可见,SourceInsight的界面就很适合多个C文件的同时编辑)
stu1.c:
#include "stu.h"void stu1_slogan()
{printf("stu1: I will be no.1!\n");
}struct student stu1 = {.name = "stu1",.score = 97.5,.s_slogan = stu1_slogan, //函数名等于其地址,所以此处是地址的赋值
};struct student* putS1inLink(struct student *head)
{struct student *p = head; if(p == NULL){head = &stu1;}else{stu1.next = head;head = &stu1;}return head;
}
stu2.c:
#include "stu.h"void stu2_slogan()
{printf("stu2: I want to make my parent proud!\n");
}struct student stu2 = {.name = "stu2",.score = 87.5,.s_slogan = stu2_slogan, //函数名等于其地址,所以此处是地址的赋值
};struct student* putS2inLink(struct student *head)
{struct student *p = head; if(p == NULL){head = &stu2;}else{stu2.next = head;head = &stu2;}return head;}
stu3.c:
#include "stu.h"void stu3_slogan()
{printf("stu3: I want to be a PC-game master!\n");
}struct student stu3 = {.name = "stu3",.score = 57.5,.s_slogan = stu3_slogan, //函数名等于其地址,所以此处是地址的赋值
};struct student* putS3inLink(struct student *head)
{struct student *p = head; if(p == NULL){head = &stu3;}else{stu3.next = head;head = &stu3;}return head;}
stu.h:
#include <stdio.h>struct student{char* name;int age;float score; //成员属性void (*s_slogan)(); //成员方法struct student *next; //链表
};struct student* putS1inLink();
struct student* putS2inLink();
struct student* putS3inLink();
main.c:
#include "stu.h"
#include <string.h>struct student* findSTUinLink(char *name, struct student *phead)
{struct student *p = phead;while(p != NULL){if(strcmp(p->name,name)==0){return p;}p = p->next;}return NULL;
}int main()
{struct student *phead = NULL;struct student *pfind = NULL;char name[64] = {'\0'};phead = putS1inLink(phead);phead = putS2inLink(phead);phead = putS3inLink(phead);if(phead == NULL){printf("Link Insert Error!\n");return 1;}while(1){printf("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n");printf("who do you want to look up?\n (pls insert 'stu1' OR 'stu2' OR 'stu3')\n");scanf("%s",name);if(strcmp(name,"stu1")==0 ||strcmp(name,"stu2")==0 || strcmp(name,"stu3")==0){pfind = findSTUinLink(name,phead);if(pfind != NULL){printf("name:%s;score:%f\n",pfind->name,pfind->score);pfind->s_slogan();}else{printf("can't find in link!\n");}}else{printf("unknown cmd!\n");}memset(name,'\0',strlen(name));}return 0;
}
在代码都编写好之后,可以全部关闭,在“factory_test”文件夹中创建一个“si”文件夹用于保存SourceInsight工程:
然后回到SourceInsight点击左上角的Project -> New Project,并选择刚刚的“si”文件夹:
然后点击两次OK,直到出现这个界面:
点击上一级的“factory_test” -> “Add All”/“Add Tree”:
最后再次点击左上角的Project -> Synchronize Files 来同步一下:
现在之前写的代码就集合成了一个工程的形式可以在SourceInsight中查看了(按住CTRL点击函数名就可以进行跳转)
并且,此时也可以继续修改代码
代码的编译和运行
现在,将“factory_test”文件夹中的代码全部发送给树莓派:
然后运行以下指令编译并运行:
1. gcc *.c -o fac
2. ./fac
可见,代码运行成功!
综上,这就是一个典型的工厂模式代码设计。对于“main.c”,相比于整体其代码量并不多,且不会向用户暴露创建逻辑。
- 结构体“student”就是一个“工厂”,是一个类;stu1,2,3作为对象以链表的形式存在在“工厂”中。
- main函数需要做的就是将“工厂”中的“模块”组装起来,然后想用哪个就去找到哪个就可以。
从上面的代码结构不难看出,使用工厂模式使得代码更稳定且拓展性更强,如果需要一个新的模块,只需要再创建一个如“stu4.c”,并将其插入结构体student中就可以,十分的方便且不会影响到其他的模块。
相关文章:
软件设计模式 --- 类,对象和工厂模式的引入
Q1:什么是软件设计模式? A:软件设计模式,又称设计模式。它是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。综上&…...
LeetCode74二分搜索优化:二维矩阵中的高效查找策略
题目描述 力扣地址 给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则&…...
三极管组成的光控开关电路原理图
什么是光控开关 光控开关/光控时控器采用先进的嵌入式微型计算机控制技术,融光控功能和普通时控器两大功能为一体的多功能高级时控器(时控开关),根据节能需要可以将光控探头(功能)与时控功能同时启用&…...
【PostgreSQL】从零开始:(四十二)系统列
PostgreSQL 中的系统列 PostgreSQL 中的系统列是一组特殊的列,用于存储关于表和视图的元数据信息。这些列是由 PostgreSQL 数据库自动创建和维护的,并且不能直接修改或删除。 每个表都有多个系统列,这些列由系统隐式定义。因此,…...
快速、准确地检测和分类病毒序列分析工具 ViralCC的介绍和详细使用方法, 附带应用脚本
介绍 viralcc是一个基因组病毒分析工具,可以用于快速、准确地检测和分类病毒序列。 github:dyxstat/ViralCC: ViralCC: leveraging metagenomic proximity-ligation to retrieve complete viral genomes (github.com) Instruction of reproducing resul…...
DNs服务学习笔记
DNS:域名系统(英文:Domain Name System)是一个域名系统,是万维网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,而不用去记住能够被机器直接读取的IP数串。类似于生活中的11…...
获取线程池中任务执行数量
获取线程池中任务执行数量 通过线程池进行任务处理,有时我们需要知道线程池中任务的执行状态。通过ThreadPoolExecutor的相关API实时获取线程数量,排队任务数量,执行完成线程数量等信息。 实例 private static ExecutorService es new Thr…...
RK3566 Android 11平台上适配YT8512C 100M PHY
RK3566代码之前适配的1000M IC RTL8211F , 现在需要在之前的基础上修改PHY IC 为裕泰的YT8512C ----------------------------------------------------------------------//将1000M 的配置关掉,改为100M 配置,查看RK3566 资料关于以太网的配置即可知道如何修改 #if…...
docker 部署haproxy cpu占用特别高
在部署mysql 主主高可用时,使用haproxy进行负载,在服务部使用的情况下发现服务器cpu占比高,负载也高,因此急需解决这个问题。 1.解决前现状 1.1 部署配置文件 cat > haproxy.cfg << EOF globalmaxconn 4000nbthrea…...
Oracle导出CSV文件
利用spool spool基本格式: spool 路径文件名 select col1||,||col2||,||col3||,||col4 from tablename; spool off spool常用的设置: set colsep ; //域输出分隔符 set echo off; //显示start启动的脚本中的每个sql命令,缺…...
图像分割实战-系列教程12:deeplab系列算法概述
🍁🍁🍁图像分割实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 1、deeplab概述 图像分割中的传统做法:为了增大感受野,通常都会选择pooling…...
数据库02-07 存储
计算机存储系统: 02.磁道存储...
WPF 入门教程DispatcherTimer计时器
https://www.zhihu.com/tardis/bd/art/430630047?source_id1001 在 WinForms 中,有一个名为 Timer 的控件,它可以在给定的时间间隔内重复执行一个操作。WPF 也有这种可能性,但我们有DispatcherTimer控件,而不是不可见的控件。它几…...
【教学类-43-04】20231229 N宫格数独4.0(n=2,4,6,8) (ChatGPT AI对话大师生成 回溯算法)
作品展示: 背景需求: 幼儿表示自己适合做5宫格 第一次AI生成九宫格数独python代码 【教学类-43-03】20231229 N宫格数独3.0(n1、2、3、4、6、8、9) (ChatGPT AI对话大师生成)-CSDN博客文章浏览阅读162次&…...
WPF美化ItemsControl1:不同颜色间隔
首先我们有的是一个绑定好数据的ItemsControl <ItemsControl ItemsSource"{Binding Starts}"> </ItemsControl> 运行后呢是朴素的将数据竖着排列 如果想要数据之间有间距,可以使用数据模板,将数据放到TextBlock中显示࿰…...
查看进程对应的路径查看端口号对应的进程ubuntu 安装ssh共享WiFi设置MyBatis 使用map类型作为参数,复杂查询(导出数据)
Linux 查询当前进程所在的路径 top 命令查询相应的进程号pid ps -ef |grep 进程名 lsof -I:端口号 netstat -anp|grep 端口号 cd /proc/进程id cwd 进程运行目录 exe 执行程序的绝对路径 cmdline 程序运行时输入的命令行命令 environ 记录了进程运行时的环境变量 fd 目录下是进…...
医院信息系统集成平台—安全保障体系
隐私保护措施 隐私保护及信息安全是医院信息平台所要重点解决的问题,应从患者同意,匿名化服务,依据病种、角色等多维度授权,关键信息(字段级、记录级、文件级)加密存储等方面展开。电子病历等医疗数据进行调阅时,包括强身份认证需求、角色授权需求、责任认…...
【信息论与编码】习题-填空题
目录 填空题1.克劳夫特不等式是判断( )的充要条件。2.无失真信源编码的中心任务是编码后的信息率压缩接近到()限失真压缩中心任务是在给定的失真度条件下,信息率压缩接近到( )。3.常用的检纠错方…...
二叉树的层序遍历经典问题(算法村第六关白银挑战)
基本的层序遍历与变换 二叉树的层序遍历 102. 二叉树的层序遍历 - 力扣(LeetCode) 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 示例 1: 输入…...
信息学奥赛一本通:装箱问题
题目链接:http://ybt.ssoier.cn:8088/problem_show.php?pid1917 题目 1917:【01NOIP普及组】装箱问题 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 4117 通过数: 2443 【题目描述】 有一个箱子容量为V�(正整数,…...
ReactNative 常见问题及处理办法(加固混淆)
ReactNative 常见问题及处理办法(加固混淆) 文章目录 摘要引言正文ScrollView内无法滑动RN热更新中的文件引用问题RN中获取高度的技巧RN强制横屏UI适配问题低版本RN(0.63以下)适配iOS14图片无法显示问题RN清理缓存RN navigation参…...
算法基础之合并果子
合并果子 核心思想: 贪心 Huffman树(算法): 每次将两个最小的堆合并 然后不断向上合并 #include<iostream>#include<algorithm>#include<queue> //用小根堆实现找最小堆using namespace std;int main(){int n;cin>>n;priority_queue&l…...
CSS 使用技巧
CSS 使用技巧 引入苹方字体 苹方提供了六个字重,font-family 定义如下:苹方-简 常规体font-family: PingFangSC-Regular, sans-serif;苹方-简 极细体font-family: PingFangSC-Ultralight, sans-serif;苹方-简 细体font-family: PingFangSC-Light, sans…...
typescript,eslint,prettier的引入
typescript 首先用npm安装typescript,cnpm i typescript 然后再tsc --init生成tsconfig.json配置文件,这个文件在package.json同级目录下 最后在tsconfig.json添加includes配置项,在该配置项中的目录下,所有的d.ts中的类型可以在…...
web前端javaScript笔记——(7)Math和Date方法
Math -Math和其他的对象不同,它不是一个构造函数, 它属于一个工具类不用创建对象,它里边封装了数学运算相关的属性和方法 比如 Math.PI 表示的圆周率 使用方法Math.方法(); Math.abs()可以用来计算一个数的绝对值 Math.ceil()可以对一…...
深入理解Java中资源加载的方法及Spring的ResourceLoader应用
在Java开发中,资源加载是一个基础而重要的操作。本文将深入探讨Java中两种常见的资源加载方式:ClassLoader的getResource方法和Class的getResource方法,并介绍Spring框架中的ResourceLoader的应用。 1. 资源加载的两种方式 1.1 ClassLoader…...
实时记录和查看Apache 日志
Apache 是一个开源的、广泛使用的、跨平台的 Web 服务器,保护 Apache Web 服务器平台在很大程度上取决于监控其上发生的活动和事件,监视 Apache Web 服务器的最佳方法之一是收集和分析其访问日志文件。 Apache 访问日志提供了有关用户如何与您的网站交互…...
Java实战项目五:文本冒险游戏
文章目录 一、实战概述二、知识点概览(一)条件分支与循环结构(二)面向对象设计(三)用户交互与事件处理 三、思路分析(一)系统架构设计(二)功能模块划分详解 四…...
docker_ROS的usb_cam使用与标定
目录 准备 准备标定板 新建容器 新建usb_cam话题的ROS功能包 编写代码 编译 运行功能包 标定 安装camera_calibration标定功能包 启动发布usb_cam话题的功能包 启动camera_calibration标定功能包 准备 usb相机 标定板 一个带有ROS的docker镜像。 准备标定板 图…...
记一次RabbitMQ服务器异常断电之后,服务重启异常的处理过程
转载说明:如果您喜欢这篇文章并打算转载它,请私信作者取得授权。感谢您喜爱本文,请文明转载,谢谢。 问题描述: 机房突然停电,rabbitmq的主机异常断电,集群服务全部需要重启。但是在执行service…...
wordpress底部CSS/app推广平台
据统计,全球范围内被投递的钓鱼邮件每天约达到1亿封,经常会遇到一些邮件发送方,被spammer利用于伪造各种钓鱼/诈骗邮件,如:伪造银行、保险等金融企业,支付宝、Paypal等支付商,知名网站、政府网站…...
设计单网站建设/百度账号登录不了
匿名用户1级2018-12-26 回答PHP 没玩过, 给你一个 C# 里面的 处理的 步骤。你对照着看看, 会不会是 thinkphp 连接 Mysql 的时候, 少传了参数。-- 创建数据库的时候, 指定字符集.CREATE DATABASE test_utf8DEFAULT CHARACTER SET utf8COLLATE…...
五台网站建设/seo优化方法网站快速排名推广渠道
**前情提要:已可将模型载入gazebo与rviz,且可用按键控制 **《教程 Re:Zero ROS (五)—— 导入模型,关节控制器》 https://blog.csdn.net/Lovely_him/article/details/107806662 教程 Re:Zero ROS (六&#…...
深圳专业制作网站的公司哪家好/网站运营课程
原文:Best Practices for Speeding Up Your Web Site 26 开发灵巧的事件处理程序 Develop Smart Event Handlers tag:javascript 如果有太多的事件处理逻辑部署在DOM树的不同元素上,它们的频繁执行会拖慢页面的响应速度。而使用事件委托是一…...
网站设计 导航条/西安网站seo诊断
Prometheus是继Kubernetes后第2个正式加入CNCF基金会的项目,容器和云原生领域事实的监控标准解决方案。在这次分享将从Prometheus的基础说起,学习和了解Prometheus强大的数据处理能力,了解如何使用Prometheus进行白盒和黑盒监控,以…...
西安做网站公司哪家比较好/天津seo优化排名
搭建QQ聊天通信的程序:(1)基于 networkcomms.net 创建一个WPF聊天客户端服务器应用程序 原文地址(英文):http://www.networkcomms.net/creating-a-wpf-chat-client-server-application/ 注意:本教程是相当广…...