在继续往下做之前,我们需要把之前的代码尽可能的精简(会对后面很有好处,而且读者也应该仔细比对这一部分的代码和上一部分哪里真正得到了优化,从而提高编程水平)。
首先数据库的操作类有哪些是可以做的更加普遍,变量名也通用的,至少要连接的目标数据库名称,目标工作薄,密码都应该是通用的,连接方法也是通用的,所以应该把连接到数据库的这个方法独立出来(我后面要写一个读写QuestionUser的类只要复制粘贴修修改改即可)
其次增查删改的几个方法,是否有必要做的更通用呢?这些方法要么输入类型要指定的结构体,要么输出类型是指定的结构体,如果复制粘贴重写一个类似的类,结构体肯定变了,每个读写的数据肯定也变了,所以这个肯定没法做的很通用(或许你可以把函数名做的很通用,比如DataBaseAdd,就是增加方法,A.DataBaseAdd就是按照A指定的记录结构增加,B.DataBaseAdd就是按照B指定的记录结构体增加,而不一定是QuestionAdd,也可能是AnswerAdd,这样做也是有好处的,读者可以自己尝试)
界面部分可以完善的代码就很多了。其实不管是新增试题还是修改试题,每个跟数据库交互的点只有两个,要么从数据库拿着数据去更新界面,要么从界面拿着数据去更新数据库。由此不管是"上一题","下一题",还是"更新此题",大部分代码都是可以复用的,你用什么方法筛选出来特定的记录我不管,但是最后更新到界面的方法都可以统一起来,由此可以有一个QuestionUpdateSetToUI方法。
同样从界面更新数据就可以叫做QuestionUpdateGetFromUI,并且把试题录入和试题查看分来,试题录入倒是没有从数据库反过来更新界面的方法(或者也可以有,录进去一个题目,自动清空文本框,准备更新下一题,不然还是不容易判断录进去没有)
关于测试题,我网上看了很多"权威"的测试题,感觉非常误导人。一个是这些题目并不适合初学者,没必要去掌握。就像你去学习开车没必要掌握发动机原理一样,甚至了解都不需要。再有一个即便要理解发动机原理也不是这么死记硬背的方式(不是你背下来了就代表你会了,什么重载,封装,委托,你像背马哲那么弄肯定考试能合格,但是没法判定你是不是真的懂)
http://blog.sina.com.cn/s/blog_485502810101dtp5.html
http://3y.uu456.com/bp_41rym11l6p8xzko047mj_3.html
我自己想了一些测试题,基本上都是要求自己编程能够实现,不管你用什么方法做出来,能做出来就是合格的,前面的简答题比如5分一个,给1分钟时间,后面的简答题10分一个,给10分钟时间(实际考试的时候随机抽12个5分的,4个10分的),问的都是应该要会的(不能问太刁钻的,比如问INT类型的数值范围,你知道不代表你厉害,你不知道也不代表你不行,那提这个问题就比较傻逼。主要还是告诉读者不要被考试题糊弄住了,考试合格只会给你发一张证,能力合格才会给你带来实实在在的钱,成天玩考试套路的那些货也不需要能力,也不会在解决问题中锻炼能力)
讲了半天废话,我们接着完善这个程序。如果点击开始考试,则开始随机抽查题目。因为前面已经有了1-20的题号,随机拿12个(60分),101-120的题号,随机拿4个(40分),那么我们首先要写一个小算法,就是给定一个起始值,终止值,然后可以生成一个随机数(更复杂一点的,要生成若干个随机数,且不能相互重复),那么首要的是实现产生一个随机数,为了快速验证,可以先用一个label和button来验证产生的数字是否在范围内。
单个数据验证之后,再来看如何产生一组随机数,且不重复(或者再从小到大排序),产生一组随机数,可以直接调用产生一个随机数的方法,这里注意写法不唯一。而且也建议用户尽量把一个复杂的功能剥离开来做成几个小方法的组合(比如产生一组随机数=产生一个随机数+判断随机数是否重复+是否需要排序等等,这些小的方法也定义在FunctionMath中,但是并不需要主程序调用,所以都做成private方法即可)
有了这个功能,我们已经可以来设计考试的模块了。假定用户点击开始考试,要在5分的题目里抽几个,再在10分的题目里抽几个。这个功能已经比较好实现了。我们之前已经有了写计算器和超级热键的经验,这里就不把变量都放在Form1里面了,而是直接新建一个类来接管整个考试的流程。先不管如何实现整个流程,我们可以规划出来要实现考试这个方法,必不可少的一些属性和方法(我们已经知道了是从一个大的集合中抽取一个小的集合,当然也可以再做一个集合认为是所有抽到的试题列表,方便程序处理),在方法上我们至少需要
初始化方法-生成新的随机试题序列
某个试题提取方法-把对应试题的编号找到数据对应的内容并显示到界面
完整考试方法-从第一题开始做到最后一题结束的整个循环的自动化处理
初始化方法已经验证过了,核心就是抽取试题,我们放到变量QuestionALL的变量中(这个变量也可以用double数组来做,用list扩展性更好,假如你后续又增加了判断题,选择题,所以题目放到一起成一个集合,题目的分值,种类和数量都变了,用数组做就不太好改),为了逐步验证,每次初始化可以输出看一下是不是按我们要求12个小题目+4个大题目出来了(序号分别为1-20和101-120的),最后设置一个Index为0,这个我们待会儿讲为什么要有这个Index
挨个试题开始考试的前提是某一个试题能够被准备从数据库读取并反映到界面上,所以我们首先要写的是单独试题的读取,注意界面该做成只读的都设置成只读,尤其是文本框,而且为了验证可以先放一些textbox往里面手动输入数字,看点击重新抽题的时候能不能准确反映到对应的试题(实际上重新抽题应该是反映随机题目序列的第一题,而不是数据库的编号为1的题目)。这里的响应我们是在Form1点击的按钮,根据结果是否为TRUE决定是否更新界面的,实际上更科学的方式是委托和事件(后面会讲到怎么做),目前先管好整个的程序流程。
从开始考试到考试结束,我们全程用一个Index来决定(上一题则Index--,下一题则Index++,确认答题也是Index++,只不过确认答题会把当前回答保存起来,是否立即存入数据库读者可以自己决定,一般题目量很少可以都存起来,等最后完成了再统一存入)。由于有了这个Index,我们针对每一题都可以有一些额外的list变量保存(当前试题是否已经作答,所耗费的时间,对应的具体回答文本等)
为了给每一题的时间限制起效果,每一题启动的时候我们要同步启动一个秒表和定时器(秒表是为了统计当前耗时,定时器是为了在主界面上显示当前耗时,并且判断如果超时就强制回答并进入下一题),先来看这个定时器,我们在主界面上放一个定时器,是最简单的办法(控件总归比写代码简单),因为不需要特别精确,默认时间间隔100ms,每隔100ms检测是否超时,如果超时则报警并进入下一题。我们在ExamHandler中定义了一个全局的布尔值CurrentTimeOverlap变量,如果不做这个变量,则一旦超时弹窗会不断的弹出来,这也是一个比较重要的编程技巧,读者需要学会。
再来看秒表的功能,秒表其实就几个方法,Reset,Start,Stop,GetTime(重置/启动/停止/获取时间),只要进入到一个新的题目,则先重置,再启动(Reset+Start),运行的时候随时可以被别人获取当前时间(GetTime),超过时间之后不再计时并获取当前时间(Stop),测试如果超时之后进入下一题,再回到上一题,显示的就不是时间限制,而是答题时间(更多的用户体验优化也可以做,比如已经回答过这个问题,则确认答题按钮不可用,不给用户犯错的机会)
答题完成,把所有信息录入新的数据库表,为此我们需要新建一个新的表(注意新的表不要填写重复信息,我们根据Question_NO已经可以到第一张表找到这个题目的分值,时间限制,具体题目内容等等,这里就没有必要再写一次,QuestionUser只需要保留用户回答的相关信息),其实还是存在多余的信息,比如只需要一个考试的ID就行了,不需要考生的名字和所在公司,公司名字和人的名字都不是唯一的,我们可以再做一张表专门保存考生的信息,目前这样做每一条考试的数据记录都会重复写一次考试姓名和所在公司
在此只做简单示意,如果再做一张数据表,这个表存储的就是用户的信息了(姓名,性别,年龄,所在公司,工作经验,参加考试时间,总的得分,其他备注等等),为了跟其他表链接起来,对每一个考生要有一个类似于身份证号一样的编号来随时找到这个用户考的哪些试题,都用了多少时间,每一题的得分(所以数据库并不是一开始就能设计的非常合理,需要不断的改进,并且是弄完了一个版本之后才发现不合理,再改进,以后再做类似的项目的时候会更有经验,少走弯路)。
有了前面的录入试题我们这里抄一份,稍微修改即可,定义一个类似的结构体,然后连接方法和增加方法都类似
具体我要交卷的时候就是遍历list,把结构挨个ADD到数据库即可(暂时不考虑非法值,也先把分值先设置为0分,在评分的栏目里可以改)
同样是ADD方法,只需要修改对应的字段即可(这里貌似不需要删除或者更新,查询的方法,在评分栏目可以做查询和更新的方法)
最后思考一下开始评分的功能(时间限制就不具体介绍了,反正后面有几个简答题还用这种流程做也不太合理),实际上开始评分应该是跟开始考试录入同一个数据库(开始考试我们把数据库的一条记录的大部分信息填写完整了,剩下的分数,最终得分,或者更多额外的信息比如考试等级都是在开始评分完成,开始评分就是先读取完成了一部分的数据记录,把这个考试的所有记录都搜出来,按编号从小到大排序,然后挨个打分并再次更新数据库就结束了,整个过程就是本质就是UPDATE,感兴趣的读者可以自己完善整个功能)
更多功能可以探讨:
如果用户提前做完一题,他是否应该得到时间的奖励?
如果用户不断的重新抽题,是否应该给与警告甚至禁止,是否应该取消上一题/下一题的查看功能?
考试结束,如何把题目完整上传到某个地方(尤其是后面10分的上级实验题,没法做自动评分,只能人工审核)?
总结:本节课程简单介绍了数据库的读写,这个看你具体做什么应用,如果做互联网相关的开发,肯定会经常碰到,传统工控行业貌似需求不大,但是往后物联网,人工智能,大数据等等比较新潮的领域也一定少不了,所谓的大数据首先要有一大批数据,肯定用TXT或者XML这种东西hold不住了。所以至少对数据库有一个基本的认识,能简单实现功能还是很有必要的。
1 理解数据库的基本操作,增查删改
2 体会数据库读写的方法改善,为什么要定义这些变量,是否在代码上还有更多精简的可能
3 不断改进代码的前后台质量,把同类的功能合并到一起,尽可能的减少重复代码,想清楚要怎么设计数据库,设计一个函数,一个类,然后再去一小块一小块的实现和验证
更多教学视频和资料下载,欢迎关注以下信息:
我的优酷空间:
http://i.youku.com/acetaohai123
我的在线论坛:
http://csrobot.gz01.bdysite.com/
问题交流:
QQ:910358960