软件设计模式 --- 类,对象和工厂模式的引入

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中就可以,十分的方便且不会影响到其他的模块。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/599779.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vmware安装redhat 7.6 操作系统

vmware安装redhat 7.6 操作系统 1、下载redhat 7.6 操作系统镜像文件2、安装redhat 7.6操作系统3、配置redhat 7.6 操作系统3.1、配置静态IP地址 和 dns3.2、查看磁盘分区3.3、查看系统版本 1、下载redhat 7.6 操作系统镜像文件 链接: 盘盘 zwzg 文件名&#xff1a;rhel-serv…

Ubuntu20 编译 Android 12源码

1.安装基础库 推荐使用 Ubuntu 20.04 及以上版本编译&#xff0c;会少不少麻烦&#xff0c;以下是我的虚拟机配置 执行命令安装依赖库 // 第一步执行 update sudo apt-get update//安装相关依赖sudo apt-get install -y libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-de…

无监督学习(K-Means)的认识

目录 一、无监督学习 二、无监督学习和有监督学习的区别 三、K-Means 3.1数据分析 3.2k-meas算法 3.3数据正态化后k-means 3.4找最佳k&#xff08;Elbow Plot&#xff09; 四、k-means算法的优缺点 一、无监督学习 无监督学习是一种机器学习的方法&#xff0c;…

掌握 Copilot:AI编程的未来

掌握 Copilot&#xff1a;AI编程的未来 前言: 欢迎来到本篇博客&#xff0c;今天我们将深入介绍一款颠覆性的编程辅助工具——Copilot。作为 GitHub Copilot 插件的使用者&#xff0c;你将体验到人工智能在编程领域的前沿应用&#xff0c;为你的代码编写提供更快、更智能的支…

车载 Android之 核心服务 - CarPropertyService 的VehicleHAL

前言: 本文是车载Android之核心服务-CarPropertyService的第二篇&#xff0c;了解一下CarPropertyService的VehicleHAL, 第一篇在车载 Android之 核心服务 - CarPropertyService 解析-CSDN博客&#xff0c;有兴趣的 朋友可以去看下。 本节介绍 AndroidAutomotiveOS中对于 Veh…

【大数据】Zookeeper 集群及其选举机制

Zookeeper 集群及其选举机制 1.安装 Zookeeper 集群2.如何选取 Leader 1.安装 Zookeeper 集群 我们之前说了&#xff0c;Zookeeper 集群是由一个领导者&#xff08;Leader&#xff09;和多个追随者&#xff08;Follower&#xff09;组成&#xff0c;但这个领导者是怎么选出来的…

PTA——逆序的三位数

程序每次读入一个正3位数&#xff0c;然后输出按位逆序的数字。注意&#xff1a;当输入的数字含有结尾的0时&#xff0c;输出不应带有前导的0。比如输入700&#xff0c;输出应该是7。 输入格式&#xff1a; 每个测试是一个3位的正整数。 输出格式&#xff1a; 输出按位逆序…

2025年考研数学题型、题量预测和真题(送35页考研数学大纲详解)

2024年考研的分数线在陆续发布中&#xff0c;在此&#xff0c;六分成长祝福所有努力奋斗的学子们都能进入考研的复试&#xff0c;并顺利录取&#xff0c;2024年9月进入自己心目中的高校、院系和专业继续深造。 与此同时&#xff0c;2025年的考研大幕已经徐徐拉开&#xff0c;现…

书生·浦语大模型全链路开源体系(陈恺|上海人工智能实验室 青年科学家)-听课笔记

大模型重要性 大模型确实已成为发展通用人工智能&#xff08;AGI&#xff09;的重要途径。它们通过整合和处理大量数据&#xff0c;学习语言、图像、声音等多种模式的表示&#xff0c;以此来模拟人类的学习和思维方式。通过不断地学习和优化&#xff0c;这些模型能够在各种任…

DBeaver配置达梦数据库连接

随着信创逐渐推广&#xff0c;达梦数据库也成为流行。下面展示如何使用dbeaver配置达梦数据库连接 1 驱动新建 菜单&#xff0c;数据库->驱动管理器 2 驱动信息填写 选择新建之后&#xff0c;弹出一个填写页面 需要填写的几个关键信息&#xff1a; 驱动名称&#xff1a;…

SpringBoot实用开发(十)-- MongoDB的安装

目录 1. 简单认识 2.使用MongoDB的场景 3.MongoDB的安装 4. MongoDB的服务启动(重点记忆)

zookeeper应用场景之分布式的ID生成器

1. 分布式ID生成器的使用场景 在分布式系统中&#xff0c;分布式ID生成器的使用场景非常之多&#xff1a; 大量的数据记录&#xff0c;需要分布式ID。大量的系统消息&#xff0c;需要分布式ID。大量的请求日志&#xff0c;如restful的操作记录&#xff0c;需要唯一标识&#x…

新手学习易语言中文编程,易语言从入门到精通教学

一、教程描述 本套教程共有100集&#xff0c;并且有大量的课件资料&#xff0c;可能是截止到目前为止&#xff0c;最为全面系统的易语言教程了&#xff0c;其中有些视频是.exe文件&#xff0c;可以下载到本地播放。本套易语言教程&#xff0c;大小14.59G&#xff0c;共有6个压…

【Java并发】深入浅出 synchronized关键词原理-下

上一篇文章&#xff0c;简要介绍了syn的基本用法和monter对象的结构&#xff0c;本篇主要深入理解&#xff0c;偏向锁、轻量级锁、重量级锁的本质。 对象内存布局 Hotspot虚拟机中&#xff0c;对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据 (Instance Da…

互联网广告行业发展历程

在20年的历程中&#xff0c;广告主与媒体方持续面对着一些问题&#xff0c;一些核心问题推动了行业的迭代。 互联网广告经过了20年左右的高速发展&#xff0c;已愈发成熟&#xff0c;其历程是有趣的。 对互联网广告发展的理解&#xff0c;网上的文章并不多&#xff0c;已有的…

第12课 利用openCV检测物体是否运动了

FFmpeg与openCV绝对是绝配。前面我们已经基本熟悉了FFmpeg的工作流程&#xff0c;这一章我们重点来看看openCV。 在前面&#xff0c;我们已经使用openCV打开过摄像头并在MFC中显示图像&#xff0c;但openCV能做的要远超你的想像&#xff0c;比如可以用它来实现人脸检测、车牌识…

【Netapp数据恢复】Netapp存储lun被删除如何恢复数据?

Netapp存储数据恢复环境&故障情况&#xff1a; 某单位一台Netapp存储&#xff0c;该Netapp存储内共有数十块SAS硬盘。 工作人员误操作删除了Netapp存储中12个lun&#xff0c;删除的数据包括客户信息和其他重要数据。 Netapp存储数据恢复过程&#xff1a; 1、将故障存储中所…

JS的异步与程序性能相关问题

1、现在与将来 1.1、分块的程序 可以把 JavaScript 程序写在单个 .js 文件中&#xff0c;但是这个程序几乎一定是由多个块构成的。这些块中只有一个是现在执行&#xff0c;其余的则会在将来执行。最常见的块单位是函数 从现在到将来的“等待”&#xff0c;最简单的方法&…

C#利用openvino部署PP-TinyPose人体姿态识别

【官方框架地址】 github.com/PaddlePaddle/PaddleDetection 【算法介绍】 关键点检测算法往往需要部署在轻量化、边缘端设备上&#xff0c;因此长期以来都存在一个难题&#xff1a;精度高、速度则慢、算法体积也随之增加。而PP-TinyPose的出世彻底打破了这个僵局&#xff0c…

43 tmpfs/devtmpfs 文件系统

前言 在 linux 中常见的文件系统 有很多, 如下 基于磁盘的文件系统, ext2, ext3, ext4, xfs, btrfs, jfs, ntfs 内存文件系统, procfs, sysfs, tmpfs, squashfs, debugfs 闪存文件系统, ubifs, jffs2, yaffs 文件系统这一套体系在 linux 有一层 vfs 抽象, 用户程序不用…