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

news2024/11/25 21:35:09

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.coloradmin.cn/o/1349939.html

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

相关文章

mysql原理--MySQL基于规则的优化

设计 MySQL 的大叔依据一些规则&#xff0c;竭尽全力的把一些很糟糕的语句转换成某种可以比较高效执行的形式&#xff0c;这个过程也可以被称作 查询重写 &#xff08;就是人家觉得你写的语句不好&#xff0c;自己再重写一遍&#xff09;。 1.条件化简 我们编写的查询语句的搜…

怎么给直播录屏?超简单教程,一学就会!

随着直播行业的兴起&#xff0c;许多玩家和观众都希望能够录制直播内容以方便随时回顾或与他人分享。可是怎么给直播录屏呢&#xff1f;本文将详细介绍两种流行的直播录屏方法。通过学习这两种工具&#xff0c;你可以轻松实现直播录屏&#xff0c;记录并分享你的直播内容。 怎么…

jsp结合servlet

servlet配置 环境配置2023.12.31 idea配置搭建 创建一个普通的java项目 由于新版idea去除了add framework support的ui显示&#xff0c;可以在左边项目栏中使用快捷键shiftk或者setting中搜索add framework support在修改对应的快捷键 点击ok然后应该就是下面这样的结果 这里…

Zookeeper-Zookeeper选举源码

看源码方法&#xff1a; 1、先使用&#xff1a;先看官方文档快速掌握框架的基本使用 2、抓主线&#xff1a;找一个demo入手&#xff0c;顺藤摸瓜快速静态看一遍框架的主线源码&#xff0c;画出源码主流程图&#xff0c;切勿一开始就陷入源码的细枝末节&#xff0c;否则会把自…

用户侧智能配电与智能用电系统的应用及未来——安科瑞 顾烊宇

摘要&#xff1a;随着科技的发展&#xff0c;电力系统正逐步向智能化、数字化、互联网化迈进。智能配电与智能用电是电力产业发展的重要方向&#xff0c;将为传统电力系统带来革命性的变革。本文将对智能配电和智能用电的概念、特点、关键技术及应用进行详细介绍。 1、智能配电…

SQL Server从0到1——基本语法

信息收集 用户&#xff1a; 当前用户名&#xff1a; select user 用户权限&#xff1a; 服务器级别&#xff1a; select IS_SRVROLEMEMBER(sysadmin) 数据库级别&#xff1a; select IS_MEMBER(db_owner) 2005的xp_cmdshell 你要知道他的权限一般是system 而2008他是nt …

云计算:OpenStack 分布式架构添加LVM存储(单控制节点与多计算节点)

目录 一、实验 1.环境 2.安装并配置控制节点 3. 安装并配置存储节点 4.使用LVM存储 一、实验 1.环境 (1) 主机 表1 主机 主机架构IP备注controller控制节点192.168.204.210已部署compute01计算节点1192.168.204.211 已部署compute02计算节点2192.168.204.212已部署sto…

Docker:部署若依前后端分离版

Docker&#xff1a;部署若依前后端分离版 1. 停止天翼云上的原来跑的若依项目2. 停止腾讯云上的若依项目3. 使用Docker部署3.1 天翼云数据库&Redis3.1.1 部署数据库3.1.2 部署Redis数据库3.1.1 部署Nginx(这里被天翼云坑了换的腾讯云运行nginx) 3.2 腾讯云部署后端&前端…

ubuntu 20.04 自由切换 python 的版本

问题描述 当前 ubuntu 20.04 默认安装了多个 python 的版本&#xff0c;执行 python 时&#xff0c;默认版本是 Python 2.7.18 zhangszzhangsz:~$ python Python 2.7.18 (default, Jul 1 2022, 12:27:04) [GCC 9.4.0] on linux2 Type "help", "copyright&quo…

【unity知识点】Unity 协程Coroutine

文章目录 前言使用协程的步骤&#xff1a;使用场景示例&#xff1a;yield return new WaitForSeconds和yield return new WaitForFixedUpdate的区别开始和停止携程完结 前言 Unity 协程是一种特殊的函数&#xff0c;可以在游戏中实现延迟执行、按顺序执行和异步操作等功能。它…

多人协同开发git flow,创建初始化项目版本

文章目录 多人协同开发git flow&#xff0c;创建初始化项目版本1.gitee创建组织模拟多人协同开发2.git tag 打标签3.git push origin --tags 多人协同开发git flow&#xff0c;创建初始化项目版本 1.gitee创建组织模拟多人协同开发 组织中新建仓库 推送代码到我们组织的仓库 2…

uni-app设置地图显示

使用前需到**高德开放平台&#xff08;https://lbs.amap.com/&#xff09;**创建应用并申请Key 登录 高德开放平台&#xff0c;进入“控制台”&#xff0c;如果没有注册账号请先根据页面提示注册账号 打开 “应用管理” -> “我的应用”页面&#xff0c;点击“创建新应用”&…

Golang leetcode707 设计链表 (链表大成)

文章目录 设计链表 Leetcode707不使用头节点使用头节点 推荐** 设计链表 Leetcode707 题目要求我们通过实现几个方法来完成对链表的各个操作 由于在go语言中都为值传递&#xff0c;&#xff08;注意这里与值类型、引用类型的而区别&#xff09;&#xff0c;所以即使我们直接在…

8个Python高效数据分析的技巧,不看肯定后悔~

本文介绍的数据分析方法&#xff0c;不仅能够提升运行效率&#xff0c;还能够使代码更加“优美”。 不管是参加Kaggle比赛&#xff0c;还是开发一个深度学习应用&#xff0c;第一步总是数据分析&#xff0c;这篇文章介绍了8个使用Python进行数据分析的方法&#xff0c;不仅能够…

实现CodeWave 低代码开发平台快速应用开发的完整指南

目录 前言1 CodeWave开发流程2 应用创建2.1 新建应用2.2 从应用模板创建应用 3 数据模型设计3.1 实体设计3.2 结构设计3.3 枚举设计 4 逻辑设计4.1 查询数据源设置4.2 组件和属性配置4.3 属性设置与服务端全局变量 5 页面设计5.1 选择页面模板5.2 前端全局变量设计5.3 事件逻辑…

音视频技术开发周刊 | 326

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 全球最强「开源版Gemini」诞生&#xff01;全能多模态模型Emu2登热榜&#xff0c;多项任务刷新SOTA 最强的全能多模态模型来了&#xff01;就在近日&#xff0c;智源研究院…

红队打靶练习:SAR: 1

目录 信息收集 1、arp 2、netdiscover 3、nmap 4、nikto 5、whatweb 小结 目录探测 1、gobuster 2、dirsearch WEB CMS 1、cms漏洞探索 2、RCE漏洞利用 提权 get user.txt 本地提权 信息收集 1、arp ┌──(root㉿ru)-[~/kali] └─# arp-scan -l Interface:…

系统学习Python——装饰器:函数装饰器-[对方法进行装饰:使用嵌套函数装饰方法]

分类目录&#xff1a;《系统学习Python》总目录 如果想要函数装饰器在简单函数和类级别的方法上都能工作&#xff0c;最直接的解决办法在于使用前面文章介绍的状态保持方案之一&#xff1a;把自己的函数装饰器编写为嵌套的def&#xff0c;这样你就不会陷入单一的self实例参数既…

【办公技巧】pdf打印没反应怎么办

正常的PDF文件是可以打印的&#xff0c;如果PDF文件打开之后发现文件不能打印&#xff0c;我们需要先查看一下自己的打印机是否能够正常运行&#xff0c;如果打印机是正常的&#xff0c;我们再查看一下&#xff0c;文件中的打印功能按钮是否是灰色的状态。 如果PDF中的大多数功…

找火鸡^^

欢迎来到程序小院 找火鸡 玩法&#xff1a;记忆翻牌游戏&#xff0c;不同关卡会有不同数目的火鸡&#xff0c;卡牌自由滚动&#xff0c;记住火鸡的位置&#xff0c; 规定的时间内找到火鸡所在的位置&#xff0c;快去找火鸡吧^^。开始游戏https://www.ormcc.com/play/gameStart…