本博客主要结合孟宁老师高级软件工程课程上的知识点,以VS Code + GCC工具集为主要环境编译调试课程项目案例menu,并仔细阅读分析源代码,结合代码分析其中的软件工程方法、规范或软件工程思想。
参考资料:
https://github.com/mengning/menu
在上篇博文中已经提前完成了C/C++插件(VSCode应用商店自带)与C/C++编译器(MinGW)的安装以及环境变量配置,这里不再赘述,具体安装细节可参考上篇博文以及参考资料
第一次调试需要配置launch.json与task.json,打开测试代码按F5出现下图,选第一项
再选第一项后自动生成launch.json与task.json
对测试结果进行调试,成功运行
首先执行Menu项目最终版本
正常执行,接下来对项目的完整开发代码进行分析
版本名 |
文件 |
文件内容描述 |
lab1 |
hello.c/menu.c |
Hello.c用于测试环境配置,menu.c是该项目基础框架,为伪代码 |
lab2 |
menu.c |
与lab1中menu.c相比,变成了可编译运行的代码,增加了quit与help命令操作,增加了头部注释 |
lab3.1 |
menu.c |
与lab2中menu.c相比,将命令作为结点存储在链表中,通过遍历链表调用命令,增加version命令,将help与quit操作写成函数 |
lab3.2 |
menu.c |
将遍历链表操作写成函数FindCmd,将help命令中显示命令以及其描述写成函数ShowAllCmd |
lab3.3 |
linklist.c/linklist.h/menu.c |
将链表操作部分分离出menu.c,其中linklist.h为声明,linklist.c为具体操作 |
lab4 |
linktable.c/linktable.h/menu.c /test.c/testlinktable.c |
命令链表增加了创建与增删改查功能,并使用信号量保证链表操作线程安全 |
lab5.1 |
linktable.c/linktable.h/menu.c /testlinktable.c |
增加了回调函数SearchCondition,回调函数的调用函数SearchLinkTableNode |
lab5.2 |
linktable.c/linktable.h/menu.c /Makefile |
增加了Makefile,告知编译器如何编译连接 |
lab7.1 |
linktable.c/linktable.h/menu.c /Makefile/menu.h/test.c |
将menu的部分功能分离出来定义为一个接口,由test.c负责调用 |
lab7.2 |
linktable.c/linktable.h/menu.c/Makefile /menu.h/test.c/readme.txt |
增加了readme.txt |
Master |
见参考链接一 |
增加了图形化的UI、显示系统时间等功能 |
模块化(Modularity)是在软件系统设计时保持系统内各部分相对独立,以便每一个部分可以被独立地进行设计和开发。模块化软件设计的方法如果应用的比较好,最终每一个软件模块都将只有一个单一的功能目标,并相对独立于其他软件模块,使得每一个软件模块都容易理解容易开发。一般我们使用耦合度(Coupling)和内聚度(Cohesion)来衡量软件模块化的程度。在软件设计中我们一般追求松散耦合。
内聚度是指一个软件模块内部各种元素之间互相依赖的紧密程度。 理想的内聚是功能内聚,也就是一个软件模块只做一件事,只完成一个主要功能点或者一个软件特性(Feather)。
项目中体现模块化思想的地方如下:
lab3.1中,将原menu.c中通过if-else语句判断的命令存储在一个链表中,加入一个新功能的时候,只需要为函数功能链表新加一个结点再写一个功能函数即可
lab3.3中,将原menu.c中命令操作的数据结构分离出来,用linklist.c存放,其中linklist.h是数据结构与方法的声明
接口具体定义了软件模块对系统的其他部分提供了怎样的服务,以及系统的其他部分如何访问所提供的服务。在面向过程的编程中,接口一般定义了数据结构及操作这些数据结构的函数;而在面向对象的编程中,接口是对象对外开放(public)的一组属性和方法的集合。函数或方法具体包括名称、参数和返回值等。
接口规格是软件系统的开发者正确使用一个软件模块需要知道的所有信息,那么这个软件模块的接口规格定义就必须清晰明确地说明正确使用本软件模块的信息。一般来说,接口规格包含五个基本要素:
接口的目的;
接口使用前所需要满足的条件,一般称为前置条件或假定条件;
使用接口的双方遵守的协议规范;
接口使用之后的效果,一般称为后置条件;
接口所隐含的质量属性。
项目中体现可重用接口设计的地方如下:
lab5.1中,用callback的机制提供了更通用的遍历链表的函数接口
在menu.c中,首先定义了一个SearchCondition函数,这个函数用来定义用户想按什么条件去查找链表,接着就在FindCmd函数中调用了SearchLinkTableNode函数,而且将SearchCondition函数作为参数传入。由于这个函数没有用到任何业务逻辑层的数据,当其他开发者想按一定条件遍历链表时,只需要定制自己的Condition函数就能方便地来调用这个遍历函数,即实现了可重用接口。
线程(thread)是操作系统能够进行运算调度的最小单位。它包含在进程之中,是进程中的实际运作单位。一个线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。一般默认一个进程中只包含一个线程。
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。 线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行读写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
lab4中,在linktable中的DeleteLinkTable、AddLinkTableNode和DelLinkTableNode使用了互斥信号量mutex对链表操作进行加锁来保证线程安全
通过阅读孟老师menu项目的各个版本的源代码,比较思考每个版本相较于前版本的差别,我对模块化设计、可重用接口、线程安全等相关知识也有了不止于理论上的理解。感谢孟老师的参考资料,今后个人学习上也会多多思考软件工程相关思想而不是埋头码代码。
原文:https://www.cnblogs.com/lcc290/p/13947908.html