正如计算机业内的一个非常经典的等式所言:
程序=算法+数据结构
软件=程序+软件工程
软件企业=软件+商业模式
现代软件企业的成功离不开优秀的软件以及杰出的商业模式,同时,作为企业运营核心的软件亦离不开软件工程的指导。
作为商业软件而言,程序是软件的“内功”,“内功”分算法和数据结构两个方面,它们共同决定了程序运行的效率,但无关乎程序的正确与否。除了程序本身之外,软件工程才真正决定了软件的命运。软件工程是指导人们如何构建和开发软件的科学,是最优的组织软件开发的方法。
总的说来,有了软件工程设计思想的“武装”,以后就为开发规范、成功的软件打下了坚实的基础。
本课程有相对应的实验课程,在实验楼网站中运行虚拟的Linux环境来进行C语言的编程。
以下是实验的心得与体会,共六篇:
在这个十分简单的“菜单”功能C程序的开发过程中,将会逐渐重现下列软件工程开发思想对软件开发的指导:
在开始的开始,还有一个十分重要的事情,那就是程序的代码风格。
什么是代码风格?什么是好的代码风格?
通常来说,代码风格就是,缩进、命名、注释等代码编排的风格规范。
好的代码风格的原则是:简明、易读、无二义性。
对于编译器来说,代码风格确实无关紧要,甚至对于一些追求极限性能的程序来说,有时候,考虑代码风格问题甚至会带来程序性能的下降(代码难以理解)。
但是,在实际开发的绝大多数场合,开发者所遇到的性能瓶颈问题,都基本不会是依靠打乱代码风格来解决的。
正相反,良好的代码风格,使程序代码简洁清晰,容易维护,也是开发人员之间的写作具有更高的效率。
(1)最原始的代码
#include
(2)引入链表,实现代码的业务逻辑和数据存储之间的分离
前文的代码十分简单,同时也存在严重的不足,就是一点用也没有。
我们的目的是写一个可重用的菜单程序,上面那个连边也摸不着。
于是,我们引入了一种数据结构:链表
typedefstructdataNode{char*cmd;char*desc;int(*handler)();structdataNode*next;}tDataNode;tDataNode*findCMD(tDataNode*head,char*cmd);voidshowAllCMD(tDataNode*head);具体实现请参见代码库。
有了链表,再对源程序改造一番!
#include
(3)改造链表,提升重用性
(2)中的链表很不完善,而且与源程序的耦合性也很强,继续改造之
(4)信息的隐藏与封装以及回调函数
typedefstructLinkListNodetLinkListNode;typedefstructLinkListtLinkList;tLinkList*CreateLinkList();intDeleteLinkList(tLinkList*pLinkList);intAddLinkListNode(tLinkList*pLinkList,tLinkListNode*pNode);intDelLinkListNode(tLinkList*pLinkList,tLinkListNode*pNode);tLinkListNode*GetLinkListHead(tLinkList*pLinkList);tLinkListNode*GetNextLinkListNode(tLinkList*pLinkList,tLinkListNode*pNode);tLinkListNode*SearchLinkListNode(tLinkList*pLinkList,intCondition(tLinkListNode*pNode,void*args),void*args);所谓回调,就是调用者调用被调用者,在被调用者执行的过程中,又去执行调用者代码段的过程逻辑。
我们在本程序中引入回调函数,是为了进一步增强链表的功能。
intSearchCondition(tLinkListNode*pNode,void*args){return(strcmp(((tDataNode*)pNode)->cmd,(char*)args)0:1);}tDataNode*FindCmd(tLinkList*head,char*cmd){return(tDataNode*)SearchLinkListNode(head,SearchCondition,cmd);}tLinkListNode*SearchLinkListNode(tLinkList*pLinkList,intCondition(tLinkListNode*pNode,void*args),void*args){if(pLinkList==NULL){returnNULL;}tLinkListNode*tmp=pLinkList->pHead;while(tmp!=NULL){if(Condition(tmp,args)==1){returntmp;}tmp=tmp->pNext;}returnNULL;}可以看出,在上述两段代码的过程逻辑中,主函数中的FindCMD调用了LinkList中的SearchLinkListNode,而在SearchLinkListNode中又使用了主函数传递过来的SearchCondition函数,这样可以做到,在主程序中定义了搜索条件,而不是预先定义在LinkList中。
通过一系列的改进,我们编写的程序做到了,在主函数中定义menu项,加入队列,自定义查询条件等一系列功能。
任务接近完成!
(5)最终的改造,接口设计
之前一系列的改造之后,menu功能实现的很顺利,是时候将整个代码封装成模块了。
intMenuConfig(char*cmd,char*desc,void(*handler)(intargc,char*argv[]));intExecuteMenu();如果我们以后想使用menu模块,就要使用上面这两个接口。第一个用来增加menu项,第二个来启动menu页面。
接口的实现:
使用示例:
MenuConfig("info","Showinformation\n\t'-author'forauthorinformation\n\t'-version'forversioninformation",info);MenuConfig("exit","Exitthisprogram",Exit);MenuConfig("time","Showtimenow",Time);#include"menu.h"intmain(){ExecuteMenu();return0;}大功告成!
近两个月的学习已经结束了,本门课程的核心在于对软件开发思想的学习,而不是纠结于具体代码的一城一池,学习本课程的最大收获,就是在一个更高的理论层次上,总览全局,对软件的总体进行把握。只有学会了高屋建瓴,才能开发出高质量的软件。
除此之外,还对本课程抱有一丝遗憾:
(有一次课程作业忘记了互评……得分减半……好可惜……本句话删除)
希望可以在课程的学习中,实际动手做出一些更具有实用价值的软件。