材 料 清 单
一、毕业论文
二、毕业设计任务书
三、毕业设计开题申请表
四、毕业设计开题报告正文
五、专业译文
1 / 70
全国计算机等级考试网上报名系统的设计与实现
全国计算机等级考试网上报名系统的设计与实现
摘 要:本文主要论述了关于全国计算机等级考试网上报名系统——基于B/S结构的设计与实现。在介绍开发系统的技术背景的基础上,主要对系统的考生报名、考试报名管理以及考试报名信息评论交流三大功能模块的设计与实现进行了论述。这几个模块基本都实现了对数据的添加、查询、修改等功能,方便考生和管理员对全国计算机等级考试网上报名的有效进行和了解相关情况。
系统整体设计思想先进,适应考试发展的需要,提供各方面最新的有关考试及报名信息,为简化报名手续、提高工作效率、方便考生特别是外地考生,方便考试管理人员随时进行报名情况的了解和管理。在操作过程中达到直观、方便、实用、安全等要求。总的说来,本系统基本上满足了全国计算机等级考试网上报名系统方面的需求。
关键词:计算机等级考试;网上报名;B/S结构;ASP.NET;SQL Server 2000
I / 70
全国计算机等级考试网上报名系统的设计与实现
Design & Implementation of The NCRE
Online Registration System
Abstract:This paper mainly discusses the national computer rank examination on-line registration system——Design and Implementation of based-on B/S structure. Introducing the development of the technical background on the basis of the main candidates for the system, the examination application, examination management and exchange of information comment on the three major functional modules for the design and implementation of the exposition. These modules are to achieve the basic data add, query, modify, and other functions, facilitate candidates and the administrator of the national computer rank examination for the effective implementation of the Internet and understand the relevant situation.
This system has advanced thought of design to meet the needs of the examination, to provide all the latest information on the examination and application, to streamline application procedures, increasing efficiency and facilitate candidates especially in the field candidates for the examination management staff at any time for the understanding and management. In the course of operations to achieve intuitive, convenient, practical and safety requirements. Overall, the system basically meet the national computer rank examination online registration system needs.
Keywords: Computer Grade Test; Online Registration; B/S structure;ASP.NET; SQL
Server 2000
II / 70
全国计算机等级考试网上报名系统的设计与实现
目 录
1 前言 ............................................................ 1
1.1 系统选取的背景及开发意义 .................................... 1
1.2 本课题的国内外研究现状 ...................................... 1 2 本系统应用的技术及其特点 ........................................ 3
2.1 B/S开发模式 ................................................ 3 2.2 ASP.NET ..................................................... 3 2.3 SQL SERVER 2000 .............................................. 4 2.4 ADO.NET ..................................................... 5 3 系统分析与设计 .................................................. 6
3.1系统需求分析 ................................................ 6 3.2系统设计建设方法三原则 ...................................... 6 3.3系统建设生命周期及生命周期方法 .............................. 6 3.4系统功能分析 ................................................ 7 3.5系统功能设计 ................................................ 8 4 数据库的设计与实现 .............................................. 9
4.1数据库理论基础 .............................................. 9 4.2数据库需求分析 ............................................. 10 4.3数据库概念结构图 ........................................... 10 4.4数据库结构逻辑设计 ......................................... 11 5 系统功能详细设计 ............................................... 13
5.1首页 ....................................................... 13 5.2考生注册 ................................................... 13 5.3考生登录 ................................................... 13 5.4管理员登录 ................................................. 15 5.5网站留言 ................................................... 18 6 系统测试 ....................................................... 20 7 系统的维护优化及展望 ........................................... 21
7.1系统的维护 ................................................. 21 7.2系统的改进 ................................................. 21 7.3系统的发展前景 ............................................. 21 8 总 结 .......................................................... 22 参考文献 ......................................................... 23 附 录 ............................................................ 24 致 谢 ............................................ 错误!未定义书签。
全国计算机等级考试网上报名系统的设计与实现
1 前言
1.1 系统选取的背景及开发意义
目前,随着科技的发展,我们已经进入了一个高速发展的信息时代。以计算机技术为核心的多媒体以及通信技术被广泛应用于各种领域。多媒体电化教学、计算机辅助教育等已在全国各地悄然兴起。根据我国考点(计算机学院)报名人数多、劳动强度大、手续繁琐等具体情况,为简化报名手续、提高工作效率、方便考生特别是外地考生,方便考试管理人员随时进行报名情况的了解和管理。为适应考试发展的需要,计算机技术考试实施网上报名是非常必要的。
计算机技术考试在全国范围已实施十多年了,随着考试规模的不断扩大,考试专业领域的扩展以及考试级别不断增加,对考试服务及管理质量提出了越来越高的要求。形势的发展要求我们必须准确、高效、快捷地做好计算机技术考试考务工作,建立公平竞争、以人为本、以法治考、民主管考的考试管理体系(考试环境),包括网上报名。再加上传统报名方式和信息管理工作在许多地区已难于适应考试发展要求,如:考生报考不方便,报名时间短,数据处理工作繁重等。目前,我国信息化程度日益普及,尤其是信息技术人员,上网已成为工作和生活的重要内容,在全国大部分地区实现网上报名的条件已经成熟。[9]
计算机技术考试实施网上报名有其独特的优势,他可以向考生提供更方便的服务。考生可以随时随地咨询和报名,灵活性强,特别是能满足许多考生的特殊需求。报名数据汇总以及信息传递快捷,操作简便;流程清晰,数据处理及时、准确。实现资源共享,管理方式更人性化,考务管理更加流程化、规范化、公开化、科学化。便于领导动态掌握报考情况,及时统计相关信息,为领导提供决策依据,便于对有关事宜提前做出安排。通过信息化、网络化的交流,便于考试管理部门与考生沟通,使领导及时了解考生的意见和要求,有利于改进考试工作。 1.2 本课题的国内外研究现状
世界各国对教育的发展给予了前所未有的关注,都试图在未来的信息社会中让教育处于一个优势的位置,从而走在社会发展的前列,为此许多国家都把信息技术应用于教育,作为民族发展的重要推动力。在国外,美国政府提出了”教育技术规划(Educational Technology Initiative) “,指出到21世纪初让全美国的每间教室和每个图书馆都将联上信息高速公路,让每个孩子都能在”21世纪教师”网络
1 / 70
全国计算机等级考试网上报名系统的设计与实现
服务。澳大利亚国家公共资源管理局已于1995年4月建立”澳大利亚教育网”,并联通Internet,该网络不仅包括全部高等院校,而且还覆盖全澳大利亚所有的中小学。
在1995年底,国外开始出现支持网上教学的系统和平台。美国的NTU、英国的OPEN COLLEGE都是十分典型的网络教育范例。网络化考试报名作为网上远程教育的重要组成部分和发展分支,己经在国外一些发达国家得到蓬勃发展,人们选学课程和考试报名都是通过网上进行。特别是Internet业务的普及,构筑高性能、低成本的计算机网络化在线考试报名,从技术条件和经济条件上己经成熟。
在国内,随着我国经济改革的进一步发展和深入,计算机技术也得到了较大的发展与普及,计算机已经成为各行各业最基本的工具之一,而且正迅速进入千家万户,有人还把它称为“第二文化”。因此,许多单位把具有一定计算机应用知识与能力作为录用、考核工作人员的重要条件。从1994年至今,全国计算机等级考试开考十几年来,得到了社会各方面的大力支持,考试规模持续增长,赢得了良好的信誉,为社会主义市场经济建设发挥了重要作用。[9]
正是因为计算机的普及,全国计算机等级考试品种增多,报名人数加大、劳动强度大、手续繁琐等具体情况。在线计算机等级考试网上报名系统设计就是针对现在计算机等级考试实行规定考点报名,方式单一,信息资料分散,经验交流不便等问题而设计的。
2 / 70
全国计算机等级考试网上报名系统的设计与实现
2 本系统应用的技术及其特点
2.1 B/S开发模式
本系统采用B/S的结构开发。B/S(Browser/Server)结构即浏览器和服务器结构。它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。这样就大大简化了客户端电脑载荷,减轻了系统维护与升级的成本和工作量,降低了用户的总体成本(TCO)。
在B/S体系结构系统中,用户通过浏览器向分布在网络上的许多服务器发出请求,服务器对浏览器的请求进行处理,将用户所需信息返回到浏览器。而其余如数据请求、加工、结果返回以及动态网页生成、对数据库的访问和应用程序的执行等工作全部由Web Server完成。随着Windows将浏览器技术植入操作系统内部,这种结构已成为当今应用软件的首选体系结构。显然B/S结构应用程序相对于传统的C/S结构应用程序是一个非常大的进步。[7]
以目前的技术看,局域网建立B/S结构的网络应用,并通过Internet/Intranet模式下数据库应用,相对易于把握、成本也是较低的。它是一次性到位的开发,能实现不同的人员,从不同的地点,以不同的接入方式(比如LAN, WAN, Internet/Intranet等)访问和操作共同的数据库;它能有效地保护数据平台和管理访问权限,服务器数据库也很安全 。特别是在JAVA这样的跨平台语言出现之后,B/S架构管理软件更是方便、快捷、高效。总体来说其分布性强、维护方便、开发简单且共享性强、总体拥有成本低,是当今世界开发模式技术架构的主流技术之一。 2.2 ASP.NET
ASP.NET是Microsoft.net的一部分,作为战略产品,不仅仅是 Active Server Page (ASP) 的下一个版本,它还提供了一个统一的 Web 开发模型,其中包括开发人员生成企业级 Web 应用程序所需的各种服务。ASP.NET 是一个已编译的、基于 .NET 的环境,可以用任何与 .NET 兼容的语言(包括 Visual Basic .NET、C# 和 JScript .NET.)创作应用程序。另外,任何 ASP.NET 应用程序都可以使用整个 .NET Framework。开发人员可以方便地获得这些技术的
3 / 70
全国计算机等级考试网上报名系统的设计与实现
优点,其中包括托管的公共语言运行库环境、类型安全、继承等等。
微软还为ASP.NET设计了这样一些策略:易于写出结构清晰的代码、代码易于重用和共享、可用编译类语言编写等等,目的是让程序员更容易开发出Web应用,满足计算向Web转移的战略需要。并且其还具有高效率、易控制、支持多种语言、更好的升级能力等新性能。
ASP.NET的新性能:ASP.net提供了稳定的性能、优秀的升级性、更快速的开发、更简便的管理、全新的语言以及网络服务。贯穿整个ASP.net的主题就是系统帮用户做了大部分不重要的琐碎的工作;全新的构造:新的ASP.net引入受管代码(Managed Code)这样一个全新概念,横贯整个视窗开发平台。受管代码在NGWS Runtime下运行,而NGWS Runtime是一个时间运行环境,它管理代码的执行,使程序设计更为简便;高效率:对于一个程序,速度是一件非常令人渴望的东西。一旦代码开始工作,接下来你就得尽可能地让它运作得快些快些再快些。在ASP中你只有尽可能精简你的代码,以至于不得不将它们移植到一个仅有很少一点性能的部件中。而现在,ASP.net会妥善地解决这一问题;易控制:在ASP.net里,你将会拥有一个“Data-Bounds” (数据约束),这意味着它会与数据源连接,并会自动装入数据,使控制工作简单易行;语言支持:ASP.net支持多种语言,支持编译类语言,支持比如VB、VC++、C#等,它比这些编译类语言运行速度快,更适合编写大型应用;更好的升级能力:快速发展的分布式应用也需要更快速、更模块化、更易操作、更多平台支持和重复利用性更强的开发,需要一种新的技术来适应不同的系统,网络应用和网站需要提供一种更加强大的可升级的服务;让你的生活更简单:通过ASP.net,我们可以看到一个新的服务控制的概念,它封装了一些普通的任务,提供了一种清晰的编程模块,有助于管理和处理不同的用户类型。[6] 2.3 SQL Server 2000
SQL Server 2000 是Microsoft 公司推出的SQL Server 数据库管理系统的最新版本。该版本继承了SQL Server 7.0 的高性能、可靠性和可扩展性的优点的同时又比它增加了许多更先进的功能,具有使用方便、可伸缩性好、与相关软件集成程度高、易于安装部署和使用等优点,可跨越从运行Microsoft Windows 98 的膝上型电脑到运行Microsoft Windows 2000 的大型多处理器的服务器等
4 / 70
全国计算机等级考试网上报名系统的设计与实现
多种平台使用。[5] 2.4 ADO.NET
ADO.NET技术是.Net Framework中访问数据一项关键技术。ADO.NET 对 Microsoft SQL Server 和 XML 等数据源以及通过 OLE DB 和 XML 公开的数据源提供一致的访问。数据共享使用者应用程序可以使用 ADO.NET 来连接到这些数据源,并检索、处理和更新所包含的数据。[4]
ADO.NET 通过数据处理将数据访问分解为多个可以单独使用或一前一后使用的不连续组件。ADO.NET 包含用于连接到数据库、执行命令和检索结果的 .NET Framework 数据提供程序。您可以直接处理检索到的结果,或将其放入 ADO.NET DataSet 对象,以便与来自多个源的数据或在层之间进行远程处理的数据组合在一起,以特殊方式向用户公开。ADO.NET DataSet 对象也可以独立于 .NET Framework 数据提供程序使用,以管理应用程序本地数据或源自 XML 的数据。
5 / 70
全国计算机等级考试网上报名系统的设计与实现
3 系统分析与设计
3.1系统需求分析
本系统主要针对全国计算机等级考试品种增多,报名人数加大、劳动强度大、手续繁琐等具体情况而设计。用以对计算机等级考试报名过程手续简化,提高工作效率,方便考试管理人员随时进行报名情况的了解和管理等。系统自从考生报名注册,考生信息查看修改;后台管理员对考生信息查看、修改、打印考生信息及确认考生报名并且分配报考号等一系列管理;以及对考试信息及报名信息的发布及评论交流等功能。系统应符合全国计算机等级考试网上报名系统的规定,满足计算机等级考试网上报名系统信息管理工作的需要并达到操作过程中的直观、方便、实用、安全等要求,从而大大减轻了考试报名的繁琐,更加方便地进行管理和维护,其经济性与实用是十分可观的。 3.2系统设计建设方法三原则
人们在复杂的系统工程建设方面,积累了较丰富的经验,为研究复杂系统,提供了科学的指导性方法论,其主要原则如下:
● 整体性原则。系统是相互联系,相互作用的诸要素组成的综合体。我们必须从整体和各组成部分的相互关系来考察事物,从整体目标和功能出发,正确处理系统各组成部分之间的相互关系和相互作用。
● 分解—协调原则。就是把复杂问题化成若干相对简单的子问题以方便求解。若子系统的问题比较复杂,还可以再分。但在处理各类子问题时,必须根据系统的整体功能和目标,协调各子系统的行为、功能与目标,以保证整体功能目标的实现。
● 目标优化原则。所谓目标优化原则对简单系统来说,是求最优解,对复杂系统来说,求的是满意解。一定要注意,目标优化原则并不简单是求最优解的问题
这里最需要指出的是:以上三原则是系统方法中处理复杂系统问题的三个主要原则,并非全部原则。在处理实际问题时,还需在这些原则的指导下,根据具体问题的特点,确定求解的具体方法和策略。[2] 3.3系统建设生命周期及生命周期方法
任何系统均有其生产、发展、成熟、消亡或更新换代的过程。这个过程我们
6 / 70
全国计算机等级考试网上报名系统的设计与实现
称之为生命周期。而生命周期法是将一个系统的生命周期划分成若干个阶段,并对每个阶段的目标、活动、工作内容、工作方法及各阶段工作之间的关系做了具体规定,以使整个建设工作具有合理的组织和科学的秩序。它是一种传统的管理信息系统开发方法,一直是大型系统开发的主流方法。步骤如下:
(一) 系统规划 (二) 系统开发
1)系统分析 包括系统逐步调查,系统的可行性研究,现行系统的详细调查,新系统的逻辑方案的提出。
2)系统设计 包括系统总体结构设计,系统总体功能设计,系统总体物理结构设计,系统详细设计,数据库设计,代码设计,输入输出设计,处理过程设计。
3)系统实现 包括程序设计,系统测试及制作安装盘。 (三) 系统的运行及维护
本系统总体上就是用了这种生命周期法进行系统分析和设计的。[2] 3.4系统功能分析
本系统主要功能如下所述: 1、首页:
首页是默认页面,主要介绍有关考试信息以及网上报名的办法、流程及注意事项等信息。 2、 考生子系统:
对于初次报考的考生,应先注册。进入注册页面后,考生应对个人信息:考生的姓名、性别、出生日期、籍贯、民族、身份证号、职业、文化程度、联系电话、电子邮件、联系地址、邮政编码;以及报考信息:所报的计算机等级及语言的完整填写。注册信息填写完整后经确认无误后提交,注册成功。
对于已经提交了报名信息的考生,可以根据考生的姓名和身份证号登录后对自己的报考信息以及个人信息的查看及相应修改。 3、 考试管理子系统:
考试管理人员登录后:可以根据考试等级查看该等级的报考信息或是根据考生个人信息(姓名/身份证号)来查看该考生的报考信息;也可以根据考生提供的身份证号来修改该考生的个人信息及报考信息;以及打印考生的相关
7 / 70
全国计算机等级考试网上报名系统的设计与实现
个人信息及报考信息;确认报名:经验证身份证号无误且已经注册过但未分配报考号的考生,采集照片后系统会按一定规律分配该考生一个相应的报考号,报名完成。 4、 留言块:
考生或是访客可以对考试及报名相关信息的发表或是交流评论留言。
3.5系统功能设计
基于B/S架构设计,在系统需求分析的基础上,得到如下图3.1所示的系统功能模块图:
首页报考注册操作登录考生个人信息查询修改留言板后台管理对考生个人信息修改打印考生信息按报考类别查询确认报名按考生个人信息查询上传照片分配报考号
图3.1系统功能模块图
8 / 70
全国计算机等级考试网上报名系统的设计与实现
4 数据库的设计与实现
4.1数据库理论基础
一个成功的系统,是建立在许多条件之上的,而数据库是其中一个非常重要的条件和关键技术。
系统所涉及的数据库设计分五个步骤:数据库需求分析、概念设计、逻辑设计、物理设计与加载测试。
(1) 数据库需求分析的任务是将业务管理单证流化为数据流,划分主题之间的边界,绘制出DFD图,并完成相应的数据字典。
(2) 概念设计的任务是从DFD出发,绘制出本主题的实体-关系图,并列出各个实体与关系的纲要表。
(3) 逻辑设计的任务是从E-R图与对应的纲要表出发,确定各个实体及关系的表名属性。
(4) 物理设计的任务是确定所有属性的类型、宽度与取值范围,设计出基本表的主键,将所有的表名与字段名英文化(现在很多软件能支持中文字段,如SQL Server 2000,我就是用的中文字段名),实现物理建库,完成数据库物理设计字典。
(5) 加载测试工作贯穿于程序测试工作的全过程,整个录入、修改、查询、处理工作均可视为对数据库的加载测试工作。[5]
要设计出一个好的系统数据库,除满足系统所要求的功能外,还必须遵守下列原则:
• 基本表的个数越少越好。
•主键的个数越少越好。键是表间连接的工具,主键越少,表间的连接就越简单。
• 字段的个数越少越好。
• 所有基本表的设计均应尽量符合第三范式。
数据库的设计中,如何处理多对多的关系和如何设计主键,是两个有着较大难度、需要重点考虑的问题。[11] 下面我们着重从SQL应用、数据库设计范式和查询优化等方面来分析本课题的系统关键技术和实现难点并加以解决。
9 / 70
全国计算机等级考试网上报名系统的设计与实现
4.2数据库需求分析
● 用户分普通考生和管理员用户 ● 每个考试等级都从属于一种类型 ● 一个考生一次只能报考一个等级 ● 一个等级可以给多个考生报考 ● 任何人都可对网站留言
经过上述的需求分析总结,设计如下的数据项和数据结构
● 管理员信息,包括数据项:帐号、密码等
● 普通考生,包括数据项:姓名、身份证号、籍贯、联系方式等 ● 报考信息表,包括数据项:考生身份证号、报考等级及语言、报考号 ● 留言表,包括数据项:留言编号、留言者姓名、留言内容、留言时间
4.3数据库概念结构图
根据以上的数据分析设计可规划出的实体有:管理员信息实体、考生信息实体、报考信息实体、留言表实体。其中各个实体之间关系的E-R图如图4.1所示。
管理员 考生 报考注册 报考等级 报考等级分类 报考信息表 留言者 留言 留言表
图4.1实体之间关系的E-R图
各个实体具体描述E-R图如图4.2——4.5所示:
10 / 70
全国计算机等级考试网上报名系统的设计与实现
管理员 姓名 帐号 ···密码 身份证号 考生 籍贯 ····· 地址 图4.2管理员信息实体图 图4.3考生信息实体图
报考信息表 留言表 报考等级 考生身份证号 报考号 留言编号 留言时间 留言者姓名 留言内容 图4.4报考信息实体图
4.4数据库结构逻辑设计
图4.5留言表实体图
经过上述的设计,现将以上的数据库概念结构转化为数据库系统所支持的实际数据模型,也就是数据库的逻辑结构。本系统涉及的数据库中用到数据表的字段和字段类型的定义,如表4.1、表4.2、表4.3 所示。
表4.1个人信息表
序号 1 2 3 4 5 6 7 8 9 10 11 12 13 14
列名 考生身份证号
姓名 性别 出生日期 籍贯 民族 职业 文化程度 联系电话 电子邮件 联系地址 邮政编码 相片 帐号
列描述
管理员登录帐号
11 / 70
类型 约束 取值 varchar(18) 主键 varchar(20) varchar(2) datetime varchar(20) varchar(20) varchar(100) varchar(20) varchar(16) varchar(30) varchar(100) varchar(6) varchar(50) varchar(20)
全国计算机等级考试网上报名系统的设计与实现
15 密码 管理员登录密码
varchar(20)
表4.2 报考信息表
序号 列名 1 考生身份证号 2 所报考等级及语言 3 报考号
列描述
类型 varchar(18) varchar(50)
int 约束 主键 取值
表4.3留言表
序号 1 2 3 4
列名 流水号 姓名 留言内容 留言时间 列描述 类型
int identity(1,1) varchar(20)
text datetime 约束 主键 取值 1
12 / 70
全国计算机等级考试网上报名系统的设计与实现
5 系统功能详细设计
5.1首页
主要是介绍考试相关信息以及网上报名的办法、流程及注意事项等信息。 5.2考生注册
该模块主要是对第一次报考的考生填写个人注册信息所用,当考生阅读完报名条款和声明后点击同意进入注册页面填写个人信息及报考信息,如图5.1所示。
图5.1考生注册页面
5.3考生登录
经验证考生输入的姓名及身份证号无误进入该考生的个人信息页面查看修改自己的个人信息及报考信息,如图5.2——5.4所示。
13 / 70
全国计算机等级考试网上报名系统的设计与实现
图5.2考生登录界面
考生登录后点击查看按钮,显示该考生注册的个人详细信息及报考信息,如图5.3所示。
图5.3考生查看个人信息
考生登录后点击修改按钮后,跳转到修改页面,修改注册信息及报考信息(对于已经分配了报考号的考生无权再修改信息),如图5.4所示。
14 / 70
全国计算机等级考试网上报名系统的设计与实现
图5.4考生修改注册信息
5.4管理员登录
管理员登录后,可按报考等级查看、按考生姓名查看,修改考生信息(与考生修改注册信息功能类似,当此考生已经分配了报考号也无权在修改),打印考生信息,确认报考(上传照片分配报考号),如图5.5——5.11所示。
图5.5管理员登录后
选中按报考等级查看单选框,点击查看按钮(也可点击考试等级下拉菜单查看该等级相应的报名人数),显示各个等级的报名人数,如图5.6所示。
15 / 70
全国计算机等级考试网上报名系统的设计与实现
图5.6按报考等级查看
选中按考生姓名查看单选框,点击查看按钮(也可点击考生姓名下拉菜单查看考生的个人详细信息及报考信息),显示各个考生的报名信息,如图5.7所示。
图5.7按姓名查看
16 / 70
全国计算机等级考试网上报名系统的设计与实现
可以按报考等级或是考生身份证号来打印相应的考生信息。输入所要打印的考生身份证号后点击打印查看按钮,跳转到该生信息页面,如图5.8所示。
图5.8打印查看
点击打印按钮调出打印页面,可以打印考生相应信息,如图5.9所示。
图5.9打印
管理员登录后点击确认报名按钮调出报名确认框,可对考生报名确认,如图5.10所示。
17 / 70
全国计算机等级考试网上报名系统的设计与实现
图5.10确认报名
输入报名考生身份证号,经验证在此之前注册过且无误并未分配报考号后,在采集其免冠照片,提交后自动为该考生分配相应的报考号,正式报名成功,如图5.11所示。
图5.11报名提交
5.5网站留言
考生或是访客可以对考试及报名相关信息的发表或是交流评论留言,默认以游客身份留言,如图5.12所示。
18 / 70
全国计算机等级考试网上报名系统的设计与实现
图5.12网站留言
19 / 70
全国计算机等级考试网上报名系统的设计与实现
6 系统测试
将一个系统开发出来并不意味着大功告成了,因为经常还会存在一些问题。我们首先要把程序拿到机器上进行试调、修改,排除其中存在的问题,使系统能正常的运行,然后再进行测试。
测试的主要技术方面介绍及测试中遇到的问题如下:
(1)功能测试:即测试软件系统的功能是否正确、完整,其依据是需求文档。由于正确性是软件最重要的质量因素,所以功能测试必不可少。就拿本系统的管理员打印考生信息模块,在开发过程中,只考虑到帮个人考生打印信息,经过测试,发现能打印个人信息,就更应该能按报考等级批量来打印,那样既能方便考生,也便于管理员的管理。
(2)健壮性测试:即测试软件系统在异常情况下能否正常运行的能力。健壮性有两层含义:一是容错能力;二是恢复能力。好比注册模块,在测试中输入的出生日期、身份证号、电子邮件等格式有误时,它并不会提示,经过测试发现后加上验证控件即可有效的解决。
(3)性能测试:即测试软件系统处理事务的速度,一是为了检验性能是否符合需求;二是为了得到某些性能数据供人们参考。还是在注册模块中,在测试时输入的出生日期和身份证号中的日期不一致时系统没有报错,发现此问题后从身份证号中把该考生的出生日期提取出来在与输入的出生日期对比,加强了考生的信息的真实性,也为考生减少出错的机率。
(4)用户界面测试:在达到功能与性能的基础上,还须测试软件系统的直观、方便、易用等效果。用户界面的简洁、直观这也是在设计系统的重中之重,必须达到用户只看了系统流程图就能知道该系统的功能以及使用方法。
总体上看,要设计一个完美的系统,测试是必不可少的一步,也是至关重要的一步,因为经过测试可以检测和发现设计过程中未想到或未处理完的问题。
20 / 70
全国计算机等级考试网上报名系统的设计与实现
7 系统的维护优化及展望
7.1系统的维护
系统的维护主要分为纠错性维护、适应性维护、完善性维护和预防性维护。 纠错性维护:由于本系统测试不可能揭露系统中存在的所有错误,所以当系统运行到一定时期后会暴露出系统内隐藏的错误,这时候要及时纠正。
适应性维护:这里指为了使本系统更好的适应环境的变化而进行的维护工作。一方面由于计算机技术的飞速发展,原来的系统不能适应新的软硬件,另一方面,应用的对象也在不断的发生变化,将导致系统不能适应新的应用环境,因此,有必要对系统进行调整,以保证系统时时都能满足用户的要求。
完善性维护:要根据用户不断提出的新要求来不断扩充原有的系统的功能。 预防性维护: 把维护工作由被动变主动,来延长本系统的使用寿命。 据统计,完善性维护占所有维护工作总数的50%左右。可见,系统维护工作中,一半以上的工作是对系统的完善,一定要多加注意。[2] 7.2系统的改进
在开发的过程中有许多不尽人意的地方,如程序的组件化,模块的划分,系统的安全性,针对这种情况可以做如下改进:
1. 各个模块可以加强独立性,能重复使用,即增加程序的耦合度; 2. 系统的开发缺乏软件工程的思想,在开发的过程中尽量多应用软件工程的思想;
3. 系统的人机界面设计不足,可以从交互性,信息的显示和数据的输入三个方面做一些加强;
4. 软件开发的过程花费时间过长,用系统的思想和系统工程的方法,结构化、模块化的至上而下对系统生命周期进行分析和设计; 7.3系统的发展前景
随着社会科技的发展,一方面,网上报名系统对我国各考点的影响会越来越重要;另一方面,网上报名系统本身也在不断的发展。虽然本系统具有一定的优点,但若不适时进行调整、改进、完善,必将被更新的、功能更完善的系统所代替。
21 / 70
全国计算机等级考试网上报名系统的设计与实现
8 总 结
在本次毕业设计过程中,通过参考各种ASP.NET编程书籍、网上查找信息以及在导师的耐心指导下,完成了此次毕业设计——全国计算机等级考试网上报名系统的设计与实现。
本次设计主要目标是采用自己较熟悉的平台和语言,设计出一个较稳定、直观、方便、实用、安全,而具有个性化的全国计算机等级考试网上报名系统。其主要是对考生报名、考试报名管理以及考试报名信息评论交流三大功能模块的设计与实现进行展开。
在设计初期,先对系统需求进行了初步的分析与了解,在通过实际的设计中遇到的问题一个一个在进行分析与解决,最终把系统分析透彻。整体上看来,从开始查找资料到对整体系统的需求分析,再从概要设计、详细设计到开始编码,以及最后的测试,整个过程感觉很良好。虽然在设计过程中遇到了不少困难,但通过针对带着某些具体的问题再次查找资料、或是向指导老师以及同学请教,最终把问题从分析到解决,设计出详细的解决方案并成功实现时,那种成就感和满足感足以鼓励自己这些时日的加班加点的辛苦。还有就是在实现系统功能需求的同时,还需考虑操作界面的直观、友好性,这也是在设计系统的重中之重,因为面对的客户有可能是没有任何电脑操作经验的人。
通过对本次系统的设计,从学的理论知识运用到实际开发,使我对软件开发有了更大的兴趣,也对软件开发流程有了更清晰的认识与了解,同时对网上报名的流程有了一个系统的认识。在开发过程还认真学习了与系统相关的知识,极大地拓宽了我的知识面,我深深的感到收获甚多。当然,由于自己水平有限,在开发的过程中也存在许多不尽人意的地方,还望大家批评指正。
22 / 70
全国计算机等级考试网上报名系统的设计与实现
参考文献
[1] 唐大仕等编. c#程序设计教程.北京:清华大学出版社,2005 [2] 邓良松,陆丽娜.软件工程. 西安电子科技大学出版社,2001 [3] 王佑中,著,Web动态技术入门, 北京:机械工业出版社,2003
[4] 柴晟等编. Ado.net数据库访问技术.北京:北京航空航天大学出版社,2006 [5] 刘卫宏. SQL Server 2000实用教程.科学出版社,2003 [6] 刘廷等著.ASP.NET 开发实例完剖析[M],北京:中国电力出版社
[7] 李闽溟,吴继刚,周学明. WEB网站开发实例导航.人民邮电出版社, 2003 [8] 王颖.敦促新理论的研究.哈尔滨工业大学硕士论文,1992
[9] 张小艳著.基于B/S模式的网上考试系统[J],工矿自动化,2002年,04期第26-28页 [10] 贾振华著.浅谈网上考试系统中自动抽题的实现[J],大众科技,2003年,04期第106-107页 [11] 李翠梅. SQL Server中数据完整性之表间关系[J] . 科技与经济.2006年第24期 107-108页
[12] 张斌 黄献波. 基于ASP.NET的用户权限设计与实现[J] .光盘技术. 2006年第3期 28-30页
[13] 宋阳 . ASP.NET的网站科研成果管理系统的设计与实现 .长春师范学院学报(自然科学版[J] . 第25卷第6期 2006年12月53-55页
[14] 夏阳 张强 陈小林. 基于ASP.NET的电子商务网站开发与设计[J] . 计算机工程与设计. 第25卷第11期 2027-2029页
[15] 王洪涛,刘文娱.深入剖析WEB编程技术及应用实例.人民邮电出版社,2004
[16] Steven Mandel . Microsoft SQL Server 2005 Stored Procedure Programming in T-SQL and .NET[J] .Net Developer's Journal Vol.5. No.5 p.22 2007
[17] J.R.McDnonell, D.Wagen.Evolving Recurrent Percepptions Time Modeling. IEEETrans.on Neural Netwoks.1994
[18] Peter Varhol . The Future of ASP.NET Hinges on Web 2.0[J] . Visual Studio Magazine Vol.17. No.1 p.40 2007
23 / 70
全国计算机等级考试网上报名系统的设计与实现
附 录
考生注册示例代码如下:
if (this.Page.IsValid) {
//获取注册的个人信息 string xb;
string xm = this.txtxm.Text.Trim(); string csrq = this.txtcsrq.Text.Trim(); string sfzh = this.txtsfzh.Text.Trim(); string jg = this.txtjg.Text.Trim();
string mz = this.ddlmz.SelectedItem.ToString(); string zy = this.ddlzy.SelectedItem.ToString(); string whcd = this.ddlwhcd.SelectedItem.ToString(); string lxdh = this.txtlxdh.Text.Trim(); string dzyj = this.txtdzyj.Text.Trim(); string lxdz = this.txtlxdz.Text.Trim(); string yzbm = this.txtyzbm.Text.Trim();
string bkdj = this.ddldjyy.SelectedItem.ToString(); //string zp = this.; if (this.rBnb.Checked) { xb = \"男\"; } else { xb = \"女\"; }
try {
SqlConnection con = DB.createConnection(); con.Open();
//检测是否已经注册过
SqlCommand cmdpd = new SqlCommand(\"select count(*) from 个人信息表 where 考生身份证号='\" + sfzh + \"'\", con);
int count = Convert.ToInt32(cmdpd.ExecuteScalar()); if (count > 0) {
Response.Write(\"\"); this.SetFocus(this.txtsfzh); } else
{
//个人信息及报考信息写入数据表中
SqlCommand cmdgr = new SqlCommand(\"insert into 个人信息表 values('\" + sfzh + \"','\" + xm + \"','\" + xb + \"','\" + csrq + \"','\" + jg + \"','\" + mz + \"','\" +
24 / 70
全国计算机等级考试网上报名系统的设计与实现
zy + \"','\" + whcd + \"','\" + lxdh + \"','\" + dzyj + \"','\" + lxdz + \"','\" + yzbm + \"',null,null,null)\", con);
cmdgr.ExecuteNonQuery();
SqlCommand cmdbk = new SqlCommand(\"insert into 报考信息表(考生身份证号,所报考等级及语言) values('\" + sfzh + \"','\" + bkdj + \"')\", con); cmdbk.ExecuteNonQuery(); con.Close();
Response.Write(\"\"); }
}
catch (Exception) {
Response.Write(\"\"); }
}
else { }
考生登录示例代码如下:
//考生登录
string strxm = this.txtdlxm.Text.Trim(); string strsfzh = this.txtdlsfzh.Text.Trim(); SqlConnection con = DB.createConnection(); con.Open();
if (strxm == \"\" || strsfzh == \"\") {
Response.Write(\"\");
//Response.Write(\"\"); } else {
//判断输入的身份证号是否存在
SqlCommand cmd = new SqlCommand(\"select count(*) from 个人信息表 where 考生身份证号='\" + strsfzh + \"'\", con);
int count = Convert.ToInt32(cmd.ExecuteScalar()); if (count > 0)
25 / 70
全国计算机等级考试网上报名系统的设计与实现
{
//判断姓名是否与输入的身份证号匹配
cmd.CommandText = \"select count(*) from 个人信息表 where 姓名='\" + strxm + \"'and 考生身份证号='\" + strsfzh + \"'\"; cmd.Connection = con;
int cun = Convert.ToInt32(cmd.ExecuteScalar()); if (cun > 0) {
this.pldh.Visible = true; this.pldl.Visible = false; this.plck.Visible = false; con.Close();
} else {
Response.Write(\"\"); } } else {
Response.Write(\"\"); }
}
报名确认示例代码如下:
//确认报考,上传照片分配报考号 //检验该生是否已在网上登记过
string strsfzh = this.txtqrsfzh.Text.Trim(); SqlConnection con = DB.createConnection(); con.Open();
SqlCommand cmd = new SqlCommand(\"select count(*) from 个人信息表 where 考生身份证号='\" +strsfzh + \"'\", con);
int count = Convert.ToInt32(cmd.ExecuteScalar()); if (count > 0) {
//判断该考生是否已经获得了报考号
SqlCommand cmdpd = new SqlCommand(\"select count(报考号) from 报考信息表 where 考生身份证号='\" + strsfzh + \"'\", con);
int pd = Convert.ToInt32(cmdpd.ExecuteScalar()); if (pd > 0)
26 / 70
全国计算机等级考试网上报名系统的设计与实现
{
Response.Write(\"\");
this.txtqrsfzh.Text = null; } else { try {
string full = this.; //获取上传文件路径
string = full(full(\"\\\\\") + 1); //获取上传文件名 string type = full(full(\".\") + 1); //获取上传文件扩展名 //this.(Server.MapPath(\"photos\") + \"\\\\\" + ); //文件存放位置
if (type == \"jpg\" || type == \"bmp\" || type == \"JPG\" || type == \"BMP\") //判断上传文件是否符合规定 {
//照片上传
this.(Server.MapPath(\"photos\") + \"\\\\\" + ); //文件存放位置
SqlCommand cmdup = new SqlCommand(\"update 个人信息表 set 相片='\" + + \"' where 考生身份证号='\" + strsfzh + \"'\", con); cmdup.ExecuteNonQuery();
//分配报考号
SqlCommand cmddj = new SqlCommand(\"select 所报考等级及语言 from 报考信息表 where 考生身份证号='\" + strsfzh + \"'\", con);
string strdj = cmddj.ExecuteScalar().ToString();
SqlCommand cmdxm = new SqlCommand(\"select 姓名 from 个人信息表 where 考生身份证号='\" + strsfzh + \"'\", con);
string strxm = cmdxm.ExecuteScalar().ToString(); int exameId = DB.examID(strdj);
SqlCommand cmdId = new SqlCommand(\"update 报考信息表 set 报考号='\" + exameId + \"' where 考生身份证号='\" + strsfzh + \"'\", con); cmdId.ExecuteNonQuery(); con.Close();
this.txtqrsfzh.Text = null;
Response.Write(\"\"); }
else {
Response.Write(\"\"); } }
catch (Exception) {
Response.Write(\"\"); } } } else {
Response.Write(\"\");
28 / 70
全国计算机等级考试网上报名系统的设计与实现
29 / 70
全国计算机等级考试网上报名系统的设计与实现
毕业论文(设计)任务书
论文题目 全国计算机等级考试网上报名系统的设计与实现 学生姓名 专业 班级 指导老师
一、 论文(设计)内容
1.熟悉web的概念;学习研究解决问题所需的工具如Microsoft Visual Studio.NET、SQL Server数据库系统的体系结构及它们之间的接口。 2.完成网上报名系统的需求分析,重点对全国计算机等级考试报名的相关信息和流程进行分析。
3.所设计的系统要能够实现对全国计算机等级考试网上报名信息及流程的有效管理,所记录的信息要全面、及时和准确,管理功能全面,安全控制符合实际需要。
4.系统设计结构合理,具有B/S结构,在Web环境中运行稳定,使用方便。 5.有关设计应符合软件工程的要求。
6.所设计的系统要能够满足考生及报名管理人员对各种信息的查询和修改的需要,统计方便准确,查询快,可以进行各种信息的相关查询,信息的安全程度高。
7.所实现的软件应该具有良好的人机交互操作界面,各功能菜单的设计合
理。
8.系统设计完成后一定要利用大量的数据对系统的各项功能进行有效的测
试并对发现的错误进行更改。
1 / 70
全国计算机等级考试网上报名系统的设计与实现
二、 论文(设计)的基本要求
1.所实现的系统要能够正常运行,能够满足系统对信息、功能、安全等方面的要求,所做的设计要符合计算机等级考试网上报名的实际需要和具有可用价值。
2.第五周完成开题报告一份,字数不少于2500字。
3.完成毕业设计报告(论文)一份,对内容阐述清楚,设计内容的表达符合软件工程规范,字数不少于10000字。
4.完成与毕业设计内容有关的英文资料的翻译,不少于5000字。
三、 进度安排
1 - 4周:根据选题进行调研,查阅有关资料,结合所需解决的问题到相关
单位实地考查或实习,搞清所需解决的问题,写出开题报告; 5 - 8周:到有关单位进行实习,实习最好能结合毕业设计选题进行,在实
习期间学习或有关工具的使用;
9 - 12周:进一步细化、完善有关设计,写出毕业设计(论文)初稿; 13 - 14周:验收设计的软件,完善毕业论文,作好毕业答辩准备。
四、 应收集的资料及主要参考文献
[1] 邓良松,陆丽娜.软件工程. 西安电子科技大学出版社,2001 [2] 王佑中,著,Web动态技术入门, 北京:机械工业出版社,2003 [3] 刘卫宏. SQL Server 2000实用教程.科学出版社,2003
[4] 张小艳著.基于B/S模式的网上考试系统[J],工矿自动化,2002年,04期 [5] 李闽溟,吴继刚,周学明. WEB网站开发实例导航.人民邮电出版社, 2003
2 / 70
全国计算机等级考试网上报名系统的设计与实现
襄樊学院毕业论文(设计)开题申请表
学生姓名 系(院) 论 文题 目 专业 指导老师 班级 全国计算机等级考试网上报名系统的设计与实现 经过一个多月的调查研究,我对计算机等级考试网上报名系统的设计有了清楚的认识,与指导老师展开了广泛的讨论,对原有的报名系统设计进行研究分析,发现了其中的一些不足之处,并拿不同的设计进行开 题 申 请 比较,认识到要设计出一个好系统将计算机技术和网络技术相结合。实现计算机等级考试在线报名、自动审核、以及考试人员数量的统计、考生信息管理和查询等可以满足不同用户的需求的功能。并将其在基于C#语言面向.NET平台开发的ASP.NET下实现该系统。通过收集多方面的资料,我对本课题已有了具体的解决方案,具备实现该课题的基本条件,特提出开题申请。 申请人签名: 年 月 日 该生经过一个月的开题准备,完成了相关资料的查阅和学习,对所选系统所涉及的数据及应该具备的功能进行了详细的分析,并在此基础指 导 教 师 意 见 上提出了较详细的解决方案,提出的方案切实可行,同意开题并进入下一阶段的系统设计。 指导教师签名: 年 月 日 注:
1.开题申请应包含申请人根据指导教师下达任务书的要求完成开题报告的基本过程,对所选课题的基本认识及开题申请;
2.指导教师意见应包含指导教师对学生开题报告的评价及开题意见; 3.学生提交申请表时须同时提交开题报告文本。
全国计算机等级考试网上报名系统的设计与实现
开题报告正文
《全国计算机等级考试网上报名系统的设计与实现》
学生姓名: 指导教师:
一、本课题选取的背景与意义
目前,随着科技的发展,我们已经进入了一个高速发展的信息时代。以计算机技术为核心的多媒体以及通信技术被广泛应用于各种领域。多媒体电化教学、计算机辅助教育等已在全国各地悄然兴起。根据我国考点(计算机学院)报名人数多、劳动强度大、手续繁琐等具体情况,为简化报名手续、提高工作效率、方便考生特别是外地考生,方便考试管理人员随时进行报名情况的了解和管理。为适应考试发展的需要,计算机技术考试实施网上报名是非常必要的。
计算机技术考试在全国范围已实施十多年了,随着考试规模的不断扩大,考试专业领域的扩展以及考试级别不断增加,对考试服务及管理质量提出了越来越高的要求。形势的发展要求我们必须准确、高效、快捷地做好计算机技术考试考务工作,建立公平竞争、以人为本、以法治考、民主管考的考试管理体系(考试环境),包括网上报名。再加上传统报名方式和信息管理工作在许多地区已难于适应考试发展要求,如:考生报考不方便,报名时间短,数据处理工作繁重等。目前,我国信息化程度日益普及,,尤其是信息技术人员,上网已成为工作和生活的重要内容,在全国大部分地区实现网上报名的条件已经成熟。
计算机技术考试实施网上报名是当今社会发展的趋势,2001年以来,国家级许多考试都相继实施了网上报名及考务信息综合管理服务。这些考试机构的网站,除了包含有考试政策、报考简章、专业设置、报考程序等必备的信息外,均有网上提交报名申请表等内容。考生不仅可以在网上查看到考试政策信息,而且能在网上报名,有的还实现了网上支付、网上订购考试用书、网上报名培训等网络化的管理手段。
计算机技术考试实施网上报名有其独特的优势,他可以向考生提供更方便的服务。考生可以随时随地咨询和报名,灵活性强,特别是能满足许多考生的特殊需求。报名数据汇总以及信息传递快捷,操作简便;流程清晰,数据处理及时、准确。实现资源共享,管理方式更人性化,考务管理更加流程化、规范化、公开
1 / 70
全国计算机等级考试网上报名系统的设计与实现
化、科学化。便于领导动态掌握报考情况,及时统计相关信息,为领导提供决策依据,便于对有关事宜提前做出安排。通过信息化、网络化的交流,便于考试管理部门与考生沟通,使领导及时了解考生的意见和要求,有利于改进考试工作。
二、本课题的国内外研究现状
世界各国对教育的发展给予了前所未有的关注,都试图在未来的信息社会中让教育处于一个优势的位置,从而走在社会发展的前列,为此许多国家都把信息技术应用于教育,作为民族发展的重要推动力。在国外,美国政府提出了”教育技术规划(Educational Technology Initiative) “,指出到21世纪初让全美国的每间教室和每个图书馆都将联上信息高速公路,让每个孩子都能在”21世纪教师”网络服务。澳大利亚国家公共资源管理局已于1995年4月建立”澳大利亚教育网”,并联通Internet,该网络不仅包括全部高等院校,而且还覆盖全澳大利亚所有的中小学。
在1995年底,国外开始出现支持网上教学的系统和平台。美国的NTU、英国的OPEN COLLEGE都是十分典型的网络教育范例。网络化考试报名作为网上远程教育的重要组成部分和发展分支,己经在国外一些发达国家得到蓬勃发展,人们选学课程和考试报名都是通过网上进行。特别是Internet业务的普及,构筑高性能、低成本的计算机网络化在线考试报名,从技术条件和经济条件上己经成熟。
在国内,随着我国经济改革的进一步发展和深入,计算机技术也得到了较大的发展与普及,计算机已经成为各行各业最基本的工具之一,而且正迅速进入千家万户,有人还把它称为“第二文化”。因此,许多单位把具有一定计算机应用知识与能力作为录用、考核工作人员的重要条件。从1994年至今,全国计算机等级考试开考十几年来,得到了社会各方面的大力支持,考试规模持续增长,赢得了良好的信誉,为社会主义市场经济建设发挥了重要作用。
正是因为计算机的普及,全国计算机等级考试品种增多,报名人数加大、劳动强度大、手续繁琐等具体情况。在线计算机等级考试网上报名系统设计就是针对现在计算机等级考试实行规定考点报名,方式单一,信息资料分散,经验交流不便等问题而设计的。
2 / 70
全国计算机等级考试网上报名系统的设计与实现
三、系统配置及开发环境
1、硬件环境要求:
CPU:Pentium III 600 内存:512M 硬盘:80G以上 2、软件环境要求:
Windows XP Professional Microsoft SQL Server 2000 Microsoft Visual Studio .NET
四、主要研究内容
1、开发设计思想:
1) 系统应符合全国计算机等级考试网上报名系统的规定,满足计算机等级
考试网上报名系统信息管理工作的需要并达到操作过程中的直观、方便、实用、安全等要求。
2) 系统采用模块化程序设计方法,既便于系统功能的各种组合和修改,又
便于未参与开发的技术维护人员补充维护。
3) 系统应具有数据库维护功能,及时根据用户需要进行数据的添加删除修
改备份等操作。 2、解决的主要问题:
简化考生报名手续、提高工作效率,方便考试管理人员随时进行报名情
况的了解和管理。 3、解决的主要技术方案
为实现本系统,主要采用的技术是基于C#语言面向.NET平台开发的
Asp.net以及ADO.NET的数据访问技术。 4、对于本系统,主要实现以下几个功能:
● 首页:
首页是默认页面,主要介绍有关考试信息以及网上报名的办法、流程及注意事项等信息。
● 考生子系统
3 / 70
全国计算机等级考试网上报名系统的设计与实现
对于初次报考的考生,应先注册。进入注册页面后,考生应对个人信息:考生的姓名、性别、出生日期、籍贯、民族、身份证号、职业、文化程度、联系电话、电子邮件、联系地址、邮政编码;以及报考信息:所报的计算机等级及语言的完整填写。注册信息填写完整后经确认无误提交。
对于已经提交了报名信息的考生,可以根据考生的报考号或是身份证号登入后对自己的报考信息以及个人信息(联系电话、电子邮件、联系地址、邮政编码)的查看及相应修改。
● 考试管理子系统:
考试管理人员登录后:可以根据考试等级查看该等级的报考信息或是根据考生个人信息(身份证号)来查看该考生的报考信息;也可以根据考生提供的身份证号来修改该考生的个人信息及报考信息;以及打印考生的相关个人信息及报考信息;确认报名:经验证身份证号无误及未分配报考号,采集照片后系统会随机分配该考生一个报考号,报名完成。
● 留言块:
考生或是访客可以对考试相关信息的发表或是交流评论留言。 5、数据库主要关系数据表:
数据是系统的核心内容,良好而规范的数据库设计是极其重要的,本系统涉及的主要数据库表与字段如下:
● 考生个人信息表,主要字段有:
考生身份证号、姓名、性别、出生日期、籍贯、民族、职业、文化程度、联系电话、电子邮件、联系地址、邮政编码、相片。
● 考生报考信息表,主要字段有:
考生身份证号、准考证流水号、所报考的计算机等级及语言、报考日期。 ● 留言表,主要字段有:
流水号、姓名、留言内容、留言时间。
4 / 70
全国计算机等级考试网上报名系统的设计与实现
6、系统功能模块设计:
基于B/S架构设计,在系统分析的基础上,得到如下图所示的系统功能模块图,如图1所示:
首页报考注册操作登录考生个人信息查询修改留言板后台管理对考生个人信息修改打印考生信息按报考类别查询确认报名按考生个人信息查询上传照片分配报考号
图1 系统功能模块图
五、进度安排
1、已完成的工作安排:
第 1 周 确定毕业设计题目。
第 2 周 下达任务书;查阅、收集有关文献资料。 第3~4周 撰写并上交开题报告。
2、待完成的工作安排:
第5~8周 根据安排进行毕业实习及课题调研。 第 5 周 进行系统需求分析和方案论证。 第 6 周 进行系统总体设计。 第7~8周 进行系统详细设计。 第9~11周 进行程序设计。
第12~13周 进行系统测试;完成毕业论文的初稿。
第 14 周 系统验收;对毕业论文进行修改并定稿;准备论文答辩。
5 / 70
全国计算机等级考试网上报名系统的设计与实现
六、主要参考文献
[1] 邓良松,陆丽娜.软件工程. 西安电子科技大学出版社,2001 [2] 王佑中,著,Web动态技术入门, 北京:机械工业出版社,2003 [3] 刘卫宏. SQL Server 2000实用教程.科学出版社,2003 [4] 刘廷等著.ASP.NET 开发实例完剖析[M],北京:中国电力出版社 [5] 萨师煊,王珊.数据库系统概论.高等教育出版社, 2006
[6] 李闽溟,吴继刚,周学明. WEB网站开发实例导航.人民邮电出版社, 2003 [7] 王颖.敦促新理论的研究.哈尔滨工业大学硕士论文,1992
[8] 张小艳著.基于B/S模式的网上考试系统[J],工矿自动化,2002年,04期第26-28页 [9] 贾振华著.浅谈网上考试系统中自动抽题的实现[J],大众科技,2003年,04期第106-107页 [10] 李翠梅. SQL Server中数据完整性之表间关系[J] . 科技与经济.2006年第24期 107-108页
[11] 张斌 黄献波. 基于ASP.NET的用户权限设计与实现[J] .光盘技术. 2006年第3期 28-30页
[12] 宋阳 . ASP.NET的网站科研成果管理系统的设计与实现 .长春师范学院学报(自然科学版[J] . 第25卷第6期 2006年12月53-55页
[13] 夏阳 张强 陈小林. 基于ASP.NET的电子商务网站开发与设计[J] . 计算机工程与设计. 第25卷第11期 2027-2029页
[14] 王洪涛,刘文娱.深入剖析WEB编程技术及应用实例.人民邮电出版社,2004
[15] Grant Palmer 著. 康博 译.C#程序员参考手册[M].清华大学出版社.2002年9月第1版.2002年9月第1次印刷
[16] Steven Mandel . Microsoft SQL Server 2005 Stored Procedure Programming in T-SQL and .NET[J] .Net Developer's Journal Vol.5. No.5 p.22 2007
[17] J.R.McDnonell, D.Wagen.Evolving Recurrent Percepptions Time Modeling. IEEETrans.on Neural Netwoks.1994
[18] Peter Varhol . The Future of ASP.NET Hinges on Web 2.0[J] . Visual Studio Magazine Vol.17. No.1 p.40 2007
6 / 70
全国计算机等级考试网上报名系统的设计与实现
专业译文
原文:
C# Primer A practical Approach
Chapter 4. Interface Inheritance
An interface specifies a set of abstract methods and properties. Like an abstract base class, an interface is made concrete by each of its derived classes. Unlike an abstract base class, an interface cannot provide a default implementation or define state, such as an instance data member or constant.
An abstract base class provides a common interface for a family of related types. In computer graphics, for example, Light may serve as an abstract base class for a family of lights. Users are likely to manipulate the lights in a scene independently of the actual type—turning them on or off, repositioning them, changing their color and intensity, and so on. The delivery of a Light hierarchy includes the abstract base class and several common derived instances, such as classes representing a spotlight, a directional light, and a point light (think of the sun). We can either make use of these prebuilt instances or derive a new instance(s). For example, in the Disney film Dinosaur we introduced a class to represent a barn-door light.
An interface, on the other hand, provides a common service or characteristic for otherwise unrelated types. For example, any type wishing to be the target of the foreach statement must implement the IEnumerable interface. For example, the ArrayList, BindingManager, DataView, and BitArray classes are all derived from the IEnumerable interface, but otherwise they have little in common. By convention, interfaces under .NET begin with a capital I followed by a mnemonic identifier with a capitalized first letter. This is a carryover from COM-based programming, which has interfaces such as IUnknown or IDirectDraw.
Unlike classes, which support single inheritance only, interfaces support multiple inheritance. The System.String class, for example, is derived from four interfaces provided within the System namespace: public sealed class String:
1 / 70
全国计算机等级考试网上报名系统的设计与实现
IComparable, ICloneable, IConvertible, IEnumerable { ... }
As C# programmers, we have three different experiences of interfaces: (1) as users of concrete instances of either the System or user-introduced interfaces, (2) as providers of a new class implementation of either the System or user-introduced interfaces, (3) as providers of a new interface class. We look at each of these three aspects in this chapter.
4.1 Implementing a System Interface: IComparable
Let's start by implementing our own class instance of a predefined interface within the System namespace. The motivational context is the following: We need to sort an ArrayList of strings in ascending order by the length of the string. OK. That sounds simple enough. So how are we going to do that? If we look at the public methods of ArrayList, we see that it provides an overloaded pair of Sort() member functions: System.Collections.ArrayList Sort: Overloaded.
Sorts the elements in the ArrayList, or a portion of it.
Let's look at the documentation for the two different methods and see which one, if either, fits the bill. Here's the one with an empty parameter list: public virtual void Sort()
Sorts the elements in the entire ArrayList using the IComparable implementation of each element.
Just by its name we know that IComparable is an interface. The element held by our ArrayList is a string. The String class implements the IComparable interface. The no-parameter Sort() method of the ArrayList uses the IComparable implementation of the String class to determine the ordering of two string objects. This imposes a dictionary order on the words—not an ordering by length. This instance, then, is not of use to us.
Okay. Maybe the next overloaded instance is useful: public virtual void Sort( IComparer ic )
Sorts the elements in the entire ArrayList using the special comparer ic.
This instance provides us with a way to override the default ordering algorithm associated with the String class. We'll create a special implementation of the
2 / 70
全国计算机等级考试网上报名系统的设计与实现
IComparer interface that sorts the strings by length. (If we were defining a class, we would include an implementation of the IComparable interface if we wanted to support sorting within the ArrayList container.)
How do we do that? What are the IComparer methods, and what do they do? Not only do we have to provide a definition of every interface member, but we must implement the documented behavior of each member if we want our implementation to transparently meld with the other implementations of that interface.
In addition, we need to throw the same exceptions under the same abnormal conditions. The compiler cannot enforce this. Recognizing and throwing the exceptions are responsibilities of the interface implementation.
It turns out there is only one method to implement. Phew! Not only that, but the implementation seems doable:
int Compare( object x, object y );
Compares two objects and returns a value indicating whether one is less than (negative number), equal to (zero), or greater than (positive number) the other.
What about any exceptions the method can throw? Again we have to look at the documentation. As it turns out, there is just one, and it also seems doable: ArgumentException
Neither x nor y implements the IComparable interface. -or- x and y are of different types and neither one can handle comparisons with the other.
This means that our implementation of the IComparer interface requires only one method: Compare(). It should throw an ArgumentException if one or both of the two arguments are invalid; in our case, that simply means that the two arguments are not both strings. Let's call the class StringLengthComparer: public sealed class StringLengthComparer : IComparer {
// first obligation: the Compare() method public int Compare( object x, object y ){...} }
Our Compare() instance must define two parameters of type object, even though our implementation is interested in only two parameters of the string type. This is
3 / 70
全国计算机等级考试网上报名系统的设计与实现
necessary because Compare() is implicitly a virtual function (as are all interface member functions), and therefore the signature of the overriding instance must exactly match the signature of the inherited method.
This is something of an inconvenience. It means we have to check within Compare()that the arguments are both of type string. If we were able to explicitly declare them as type string, the compiler would enforce that type requirement automatically. We'll see how to get around that—at least partially—in Section 4.4. The only thing left now is the implementation of Compare(). We can break that down into two primary steps. First we must confirm the validity of the two arguments. That done, we must compare the lengths.
We have two parameters of type object, and we must confirm that they are really instances of type string. One strategy is to use the is operator: if (( ! ( x is string )) || ( ! ( y is string )))
throw new ArgumentException( \"some dire message\" );
// OK: arguments are valid;
// let's cast them to string objects string xs = (string) x; string ys = (string) y;
Alternatively, we can allow the as operator to do the downcasting. We throw an exception if either xs or ys is set to null:
string xs = x as string; string ys = y as string;
if ( xs == null || ys == null )
throw new ArgumentException( \"some dire message\" ); That's really the only tricky part. Here is the length comparison: int ret_val = 1;
if ( xs.Length < ys.Length ) ret_val = -1; else
if ( xs.Length == ys.Length ) ret_val = 0; return ret_val;
So we've implemented our first concrete instance of an interface class. Here is how we might invoke Sort():
ArrayList stringList = new ArrayList();
4 / 70
全国计算机等级考试网上报名系统的设计与实现
// fill it up
stringList.Sort( new StringLengthComparer() ); 4.2 Accessing an Existing Interface
In this section we implement a generic binary tree that holds node values of any type. As you know by now, the way we do that in C# is to declare the node to be of type object. As an additional wrinkle, a node value is inserted only once within a tree. If it occurs another time, we increment an occurrence count. This gives us the chance to look at the IComparable interface. The node class is called TreeNode: public sealed class TreeNode {
private int m_occurs; private object m_nval;
private TreeNode m_lchild, m_rchild;
// ... }
For our tree we'll implement several policies that provide opportunities for exercising some of the interfaces defined within the .NET framework. For example, we want to fix the type of the tree after inserting the first element. The tree class is called BinaryTree:
public class BinaryTree {
public delegate void Action( ref TreeNode node); private Type m_elemType; private TreeNode m_root;
private Action m_nodeAction; // ... }
When the user creates a BinaryTree object, we want it to be able to hold a value of any type. We support that capability by using the type object. Once the user inserts a value, however, we want all the remaining values inserted in that tree to be of the same type. The insertion of a first value locks the type of that tree.
For example, here is how our tree must behave. When we create a new tree, it can hold objects of any type. Once we have inserted an element, however, the tree can store only other elements of that type. For example, when we write BinaryTree bt = new BinaryTree();
5 / 70
全国计算机等级考试网上报名系统的设计与实现
bt can potentially store elements of any type. However, once we write bt.insert( \"Piglet\" );
bt becomes a binary tree that holds elements of type string. Subsequent insertions of string elements, such as bt.insert( \"Eeyore\" ); bt.insert( \"Roo\" );
are fine. Each element is inserted within the tree according to the ordering supported by the IComparable interface.
What we want to prevent is a subsequent attempt by the user, after having inserted an object of one type, to insert an object of a different type. For example, if the user writes bt.insert( 1024);
we want to recognize and flag that the type being inserted is different from the type to which we've previously bound our tree. To do this, we'll throw an exception. We'll make no further constraints on objects in order for them to be accepted as tree node values. Only types that implement the IComparable interface are accepted. Why? Because each element is passed to us through the object parameter, so we have lost all compile-time type information. The interface provides an ordering service that is type independent—for example,
private IComparable confirm_comparable( object elem ) {
IComparable ic = elem as IComparable; if ( ic == null ){
string msg = \"Element type must support IComparable -- \" + elem.GetType().Name
+ \" does not currently do so!\"; throw new ArgumentException( msg ); }
return ic; }
Here is how we might invoke confirm_comparable(): public void insert( object elem ) {
// if this is the first element if ( m_root == null ){
6 / 70
全国计算机等级考试网上报名系统的设计与实现
confirm_comparable( elem ); m_elemType = elem.GetType(); m_root = new TreeNode( elem ); } else {
confirm_type( elem );
m_root.insert_value( elem ); } }
insert() checks the element's suitability only with the first insertion of an object of that type. Subsequently, it simply confirms that the new object is of the same type as the initial object. If it is, we insert the element within the tree, as shown here: public void insert_value( object val ) {
// assumption is that BinaryTree has confirmed this ... IComparable ic = val as IComparable;
// OK: zero means the two objects are equal if ( ic.CompareTo( m_nval ) == 0 ){ m_occurs++; return;
}
// OK: less than; insert within left subtree if ( ic.CompareTo( m_nval ) < 0 ){ if ( m_lchild == null )
m_lchild = new TreeNode( val ); else m_lchild.insert_value( val ); }
else { // insert within right subtree if ( m_rchild == null )
m_rchild = new BTreeNode( val ); else m_rchild.insert_value( val ); } }
When we manipulate an object's actual type, we can pretty much ignore whatever interfaces that type implements. When we manipulate an entity of type object, however, the discovery and use of an interface becomes critical because all compiletime type information is lost. (Alternatively, we can query the object at runtime as to its actual type. We look at type reflection in Section 8.2.)
7 / 70
全国计算机等级考试网上报名系统的设计与实现
4.3 Defining an Interface
In Section 4.1 we implemented a new instance of an existing interface. In Section 4.2 we simply discovered and used the interface associated with a given type. In this section we introduce an interface definition. This interface supports the generation and display of sequences of numbers based on a unique algorithm. Here is the general set of operations we wish to support (two methods, a property, and an indexer): * GenerateSequence(), which generates the unique sequence of elements * Display(), which outputs the elements
* Length, which returns a count of the number of elements * Indexer, which allows the user to access a specific element
An interface definition begins with the keyword interface followed by a name. Recall that in .NET, interfaces by convention begin with a capital I. The name follows, beginning with a capital letter, although this convention is not enforced by the compiler. We'll call our interface INumericSequence: public interface INumericSequence{}
Yes, it is legal to define an empty interface, so this represents a complete interface definition.
The members that an interface is permitted to define are a subset of those permitted for a class. An interface can declare only methods, properties, indexers, and events as members—for example,
public interface INumericSequence {
// a method
bool generate_sequence( int position );
// a set of overloaded methods void display();
void display( int first );
void display( int first, int last );
// a property
int Length { get; }
// a one-dimensional indexer
8 / 70
全国计算机等级考试网上报名系统的设计与实现
int this[ int position ]{ get; } }
All members of an interface are implicitly abstract. We cannot provide a default implementation, however trivial. In addition, the members of the interface are implicitly public. We cannot modify a member with either the abstract or the public keyword.
An interface cannot define instance data members. Nor can it define either a constructor or a destructor. (Without state members, neither is required.) In addition, an interface cannot declare static members. Because a const member is implicitly static, const members are not allowed, and neither are operators nor, not surprisingly, a static constructor.
An interface can inherit from another interface: public interface INumericSequence : ICollection { ... } or from multiple interfaces:
public interface INumericSequence
: ICollection, ICloneable { ... }
but an interface cannot explicitly inherit from a class or struct. All interfaces, however, implicitly inherit from the root Object class. 4.3.1 Implementing Our Interface: Proof of Concept
Once we have defined our interface, how can we tell if it is any good? Typically, in addition to defining the interface, we deliver at least one implementation—as a kind of proof of concept or sanity check to confirm the viability of the interface. Let's provide a Fibonacci implementation to test our interface.
The first two elements of the Fibonacci sequence are both 1. Adding the two previous elements generates each subsequent element. For example, the first eight Fibonacci elements are 1, 1, 2, 3, 5, 8, 13, 21. So what do we do first?
An interface is implemented by either class or struct inheritance. A struct isn't appropriate in this case: We don't expect to be creating and manipulating lots of Fibonacci objects in time-critical portions of the application. We'll declare Fibonacci as a class then. Because we do not expect it to be subsequently derived from, we'll declare it to be sealed as well:
9 / 70
全国计算机等级考试网上报名系统的设计与实现
public sealed class Fibonacci : INumericSequence {}
This empty definition, however, is illegal. A class inheriting from an interface must provide an implementation of every interface member. Leaving out even one member results in a compile-time error. (The exception is any case in which the class implementing the interface is abstract. It can then declare one or more of the interface member functions abstract. This is illustrated in Section 4.5.)
Before we can implement the interface members, we must determine the state information necessary to support the sequence abstraction. In this case we'll need an array to hold the sequence elements, and two additional members to hold the size and capacity of the array. Because the elements of the sequence are invariant, we need only a single array. We'll declare the array and its two supporting members as static. The implementation of an interface has two main elements: (1) providing the underlying infrastructure, if any, to support the abstraction, and (2) providing a definition for each member of the interface, including the members of all inherited base interfaces. Here is the skeleton of a Fibonacci class design: public sealed class Fibonacci : INumericSequence {
// infrastructure to support sequence abstraction private static int [] m_elements; private static short m_count;
private static short m_capacity = 128;
// Fibonacci-specific methods:
// all for infrastructure supports static Fibonacci(){ ... }
private void check_pos( int pos ) { ... } private void grow_capacity() { ... }
// INumericSequence inherited members
public bool generate_sequence( int pos ) { ... }
public void display(){ ... }
public void display( int first ) { ... }
public void display( int first, int last ) { ... }
public int Length { get{ return m_count; }} public int this[ int position ] { ... }
10 / 70
全国计算机等级考试网上报名系统的设计与实现
}
The indexer has to verify the validity of the position, of course. I've factored that verification into a private member function, check_pos(). If the position is invalid, an exception is thrown. Otherwise the indexer returns the element, decrementing the position by one:
public int this[ int position ] {
get {
check_pos( position );
return m_elements[ position-1 ]; } }
Because array indexing in C# is zero based—that is, the first element is retrieved with an index of 0—we must adjust the position specified by the user. Why not require the user to make that adjustment explicitly? Whether that's a good decision or not depends on the perceived sophistication of our users. If they are other software developers, requiring the index to be zero based might well make sense. Nonprogrammers, however, often find the notion of a first element being at position zero very unnatural. By encapsulating the adjustment within the class, we shoulder the burden and make using our code safer and more pleasant for our users.
Here is how we might exercise our implementation. First we program an instance directly as a Fibonacci class object. Next we program it indirectly as a generic INumericSequence object:
public static void Main() {
// just some magic numbers – used as positions const int pos1 = 8, pos2 = 47;
// let's directly use interface through class object Fibonacci fib = new Fibonacci();
// invokes indexer;
// indexer invokes generate_sequence( pos1 ); int elem = fib[ pos1 ];
int length = fib.Length;
11 / 70
全国计算机等级考试网上报名系统的设计与实现
string msg = \"The length of the INumericSequence is \"; Console.WriteLine( msg + length.ToString() ); Console.WriteLine(
\"Element {0} of the Fibonacci Sequence is {1}\ pos1, elem ); fib.display();
// OK: let's now use interface generically INumericSequence ins = fib;
elem = ins[ pos2 ]; length = ins.Length;
Console.WriteLine( msg + length.ToString() ); Console.WriteLine(
\"Element {1} of the Fibonacci Sequence is {0}\ elem, pos2 );
ins.display( 44, 47 ); }
As it turns out, our implementation is somewhat flawed. (That's the point of testing it.) The problem is self-evident in the program's output:
The length of the INumericSequence is 8 Element 8 of the Fibonacci Sequence is 21 Elements 1 to 8 of the Fibonacci Sequence: 1 1 2 3 5 8 13 21
The length of the INumericSequence is 47
Element 47 of the Fibonacci Sequence is -1323752223 Elements 44 to 47 of the Fibonacci Sequence:
701408733 1134903170 1836311903 -1323752223
What's going on here? The program claims that the forty-seventh element of the Fibonacci sequence is -1323752223. That's really not right. If we look at the display of elements 44 through 47, what has happened is pretty clear:
Elements 44 to 47 of the Fibonacci Sequence:
701408733 1134903170 1836311903 -1323752223
We have declared m_elements to hold elements of type int. Unfortunately the forty-seventh Fibonacci element is too large to be contained within an int. The value overflowed into the sign bit, so the value is incorrectly displayed as negative. To better handle large Fibonacci values, we need to redefine m_elements as a type able to hold larger values.
12 / 70
全国计算机等级考试网上报名系统的设计与实现
What type is the most appropriate? In addition to the integral types, there are two floating-point types (the single-precision float and the double-precision double) and the 28-digits-of-precision decimal type. Let's redeclare m_elements to be, in turn, a uint, a ulong, a decimal, and a double. At position 50, only the ulong, decimal, and double are left standing:
Fibonacci Element #50 : (int) : -298632863 Fibonacci Element #50 : (uint) : 3996334433 Fibonacci Element #50 : (ulong) : 12586269025 Fibonacci Element #50 : (decimal) : 12586269025 Fibonacci Element #50 : (double) : 12586269025
At position 100, only the decimal and double are capable of representing the value. However, the double begins to lose precision by rounding, which is unacceptable. Only the decimal values do not round off. Our best choice for representing the elements of the Fibonacci sequence is thus the decimal type: Fibonacci Element #100 : (ulong) : 37367171
Fibonacci Element #100 : (decimal) : 354224848179261915075 Fibonacci Element #100 : (double) : 3.54224848179262E20
Still, however, this is not a complete solution. The decimal type reaches its 28-digit limit at position 139:
Fibonacci Element #139 :(decimal): 5583911
Fibonacci Element #139 :(double) : 5.58406E28
When we attempt to calculate position 140, the decimal object overflows and the following exception occurs:
System.OverflowException:
Value is either too large or too small for a Decimal.
at System.Decimal.Add(System.Decimal, System.Decimal)
at System.Decimal.op_Addition(System.Decimal, System.Decimal) at Project1.Fibonacci.version_decimal(Int32) at Project1.MainObj.Main()
We can store and display only the first 139 Fibonacci elements using the predefined C# arithmetic types. Unless we plan to implement our own numeric class supporting very large integral values, we'll need to define a limit to the element position a user can request. Because this holds true for any numeric sequence, we should add that limit definition to the INumericSequence interface, as follows:
13 / 70
全国计算机等级考试网上报名系统的设计与实现
public interface INumericSequence {
// the two new properties int Length { get; } int MaxPosition { get; } // ... rest the same ... }
public sealed class Fibonacci : INumericSequence {
// infrastructure to support sequence abstraction
private static int [] m_elements = new int[ m_maxpos ]; private static short m_count;
private const short m_maxpos = 128;
public int MaxPosition { get{ return m_maxpos; }}
// ... rest the same, except no longer need to grow array }
This means that there is an infinite set of Fibonacci element positions that are legitimate but that we can't easily support and, in fact, have chosen not to support. In addition, the user might specify an invalid position—any value less than or equal to zero. How should we handle these two invalid conditions? The convention in both C# and .NET programming is to report all program anomalies through the raising of an exception.
But which exception should it throw? Should it throw separate exceptions for an invalid position and an unsupported position? There is no single right answer. Who should decide? If each interface implementation is allowed to decide whether and what exceptions to throw, if any, it becomes nearly impossible to safely program the interface generically. For example, to write the following code sequence: INumericSequence ins = o as INumericSequence; if ( ins != null )
elem = ins[ pos2 ];
we must know that every implementation of the indexer reports an invalid position in exactly the same way.
This means that the interface definition must decide under what conditions an exception must be thrown and what the exception should be. Unfortunately, we can do
14 / 70
全国计算机等级考试网上报名系统的设计与实现
that only through documentation. There is no way within C# to directly associate a member with one or a set of exceptions it may throw.
15 / 70
全国计算机等级考试网上报名系统的设计与实现
中文翻译:
4、接口继承
接口详细说明了一组抽象的methods和properties。和abstract base class一样,接口依靠derived class将它塑造为具体实物而非抽象接口。和abstract base class不同的是,接口不能提供缺省实现或是定义任何“状态”,例如定义实体数据成员或常量。
Abstract base class为一整族相关型别提供了公共的接口。例如在计算机图形学中,light可能作为一族发光体的abstract base class,用户可能在一组场景中以“与实际型别无关”的方式来操纵这些发光体,包括开启或熄灭、调换位置、改变颜色和亮度、如此等等。整个Light体系包含abstract base class、数个derived class也许代表聚光灯、定向灯、点光源(如太阳等等)。我们可以利用这些预先建立好的classes。或从中再派生出的新的classes。例如在迪斯尼电影《恐龙》一片中,我们引入了一个新的class,代表“有挡光板的照明灯”。
换句话说,接口为“在其他方面互不相干”的型别提供了一些公共服务和特征。例如打算被用于foreach语句的型别,都必须实现出IEnumerable接口,但除此之外它们鲜有共同处。
在C#之中,class只支持单一继承,但接口却支持多重继承。例如class System string是从System命名空间提供的4个接口派生而来: public sealed class String:
IComparable, ICloneable, IConvertible, IEnumerable { ... }
C#程序员可以以三种不同的方式来使用接口:(1)使用“根据System所提供或用户自定义之接口”而实现出来的具体classes;(2)为“System提供或用户自定义”之接口实现具体的class;(3)提供新的接口。本章将分别谈论以上三个方面。
4.1 实现System 接口:IComparable
让我们以“为system命名空间中预定义之接口实现出自己的class”作为旅途的开始。背景动机如下:我们需要依照字符串长度,由小到大,对内含string的ArrarList排序。很好,听起来够简单的,但怎么做呢?观察ArrayList的public成员函数,我们便能发现,它提供一组重载的Sort()成员函数: System.Collections.ArrayList Sort: Overloaded. (已重载)
1 / 70
全国计算机等级考试网上报名系统的设计与实现
Sorts the elements in the ArrayList, or a portion of it. (将ArrayList中的所有元素或部分元素排序)
现在让我们读一读这些重载函数的文档,看看哪一个合用。以下是不带参数的sort():
public virtual void Sort()
Sorts the elements in the entire ArrayList using the IComparable implementation of each element. (以元素所实现出来的IComparable为排序准则,对整个ArrayList内的元素排序)
从名字就能知道IComparable是一个interface,我们的ArrayList持有的元素是string,而string已实现出IComparable,ArrayList提供的无参数sort()将以“string所具备之IComparable实现”来决定两个string objects的顺序。不过,那是单词的字典顺序,不是以长度为评断的顺序。因此,这份sort()函数实体对我们没有用。
好,也许下面这份重载实体有用:
public virtual void Sort( IComparer ic )
Sorts the elements in the entire ArrayList using the special comparer ic.
(以特定的比较器’ic’为排序准则,对整个ArrayList的所有元素排序)
这份实体为我们提供了一个改变string class缺省排序算法的途径。我们将为IComparer创建一份特殊实现——按长度对字符串排序。如果我们定义某个class并打算将此class装入容器ArrayList内进行排序,我们就得在实现该class时含入IComparable。
我们该怎么办?IComparer成员函数有哪些?它们是干什么的?如果想让我们的实现与此接口的其他实现能够无缝接合,那么我们不仅要为每个接口成员函数提供定义,还必须为每个成员函数实现出文档所规定的行为。
此外,在相同的情况下,我们应该抛出相同的异常。编译器不能强迫我们这么做。识别并抛出异常是接口实现品的责任。
文档显示只一个成员函数需要我们实现,嗯,做起来也没什么困难: int Compare( object x, object y );
Compares two objects and returns a value indicating whether one is less than (negative number), equal to (zero), or greater than (positive number) the other.
(比较两个objects并返回一值:如果第一参数小于、等于或大于第二参数,就
2 / 70
全国计算机等级考试网上报名系统的设计与实现
分别返回负数、零或正数)
这个成员函数能抛出哪些异常呢?我们再次查看文档,正如所见,只能抛出一个异常,这看来也是可行的:
ArgumentException
Neither x nor y implements the IComparable interface. -or- x and y are of different types and neither one can handle comparisons with the other.
(x、y都没有实现IComparable。或者x和y型别不同,无法相互比较)
这意味着我们的IComparer实现品只须一个成员函数:Compare()。如果引数不合法,它应该抛出ArgumentException异常;对我们而言,引数不合法仅仅意味着两个引数不全是string,我们将class命名为stringLengthComparer: public sealed class StringLengthComparer : IComparer {
// first obligation: the Compare() method public int Compare( object x, object y ){...} }
即使我们的实现品只对明确的两个string参数感兴趣,我们的Compare()实体也必须将两个参数的型别定义为泛化的object,这么做是因为Compare()暗自是个虚函数,因为覆写的函数实体的标记式必须和继承而来的成员函数的标记式完全吻合。
这一点不够方便,这意味着我们得在compare()中检验其引数型别是否为string。要是我们能明确地将其型别声明为string,编译器就能自动实施型别检测。我们将在4.4节解释如何绕开它——至少从部分意义上来说如此。
剩余要做的唯一一件事就是实现Compare()。实现过程可分解为两大步骤。首先必须确认两个引数的合法性,而后比较其长度。
我们有两个“型别为object”的参数,而且必须确认它们其实都是型别string的实体。策略之一是利用is操作符:
if (( ! ( x is string )) || ( ! ( y is string )))
throw new ArgumentException( \"some dire message\" );
// OK: arguments are valid;
// let's cast them to string objects string xs = (string) x; string ys = (string) y;
另一个策略是以as操作符进行向下转型。如果xs或ys之一被设为null,我
3 / 70
全国计算机等级考试网上报名系统的设计与实现
们就能抛出异常:
string xs = x as string; string ys = y as string;
if ( xs == null || ys == null )
throw new ArgumentException( \"some dire message\" );
以上是唯一棘手的部分。以下是长度比较: int ret_val = 1;
if ( xs.Length < ys.Length ) ret_val = -1; else
if ( xs.Length == ys.Length ) ret_val = 0; return ret_val;
这样看来,我们已经实现出接口的第一个具体实体。下面调用Sort(): ArrayList stringList = new ArrayList(); // fill it up
stringList.Sort( new StringLengthComparer() );
4.2 访问业已存在的接口
本节中我们将实现一个泛型二叉树,其内可持有任何型别的节点。正如你现在知道的,在C#中的实现办法就是将节点型别声明为object。此外,一个节点值只安插到树中一次;如果节点值再次出现,我们就将它的出现次数累加1。这个例子使我们有机会仔细体会IComparable。我把节点成为TreeNode: public sealed class TreeNode {
private int m_occurs; private object m_nval;
private TreeNode m_lchild, m_rchild;
// ... }
我将为这颗树实现出诺干政策。为它提供运用.NET Framework所定义的一些接口的机会,例如我们想在插入第一个元素之后将树的型别固定下来。我的这颗树名为BinaryTree:
public class BinaryTree {
public delegate void Action( ref TreeNode node); private Type m_elemType; private TreeNode m_root;
4 / 70
全国计算机等级考试网上报名系统的设计与实现
private Action m_nodeAction; // ... }
用户创建一个BinaryTree object时,我想让它能够持有任何型别的元素。只要将元素型别指定为object便可以做到这一点。然而一旦用户插入第一个值,我们便希望从此所有后继插入的元素,型别皆与第一元素相同。也就说,被插入的第一个元素锁定了树的型别。
以下是这棵树的必要行为:当我们创建一颗树,他能持有任何型别的pbjects:一旦插入第一个元素,这棵树就只能存储与第一元素的型别相同的其他元素。例如,当我们写下:
BinaryTree bt = new BinaryTree();
bt可以存储任何型别的元素。然而,一旦我们写下: bt.insert( \"Piglet\" );
bt就变得只能持有型别为string的元素。接下来插入其他string元素都没有问题: bt.insert( \"Eeyore\" ); bt.insert( \"Roo\" );
每个元素都将依照IComparable所保证的顺序插入树中。
现在我们希望阻止用户插入第一个元素后,又插入与第一个元素型别不同的object。例如用户写下: bt.insert( 1024);
我希望将目前插入之元素,其型别与先前确认的型别不符这一错误消息表示出来。要做到这一点,抛出异常即可。
除了要求只接受实现出IConparable的型别之外,对于树节点,我们在没有更多约束了,为什么?因为每个元素都是通过object参数传进来的,所有编译期型别信息都已丢失。ICompatable提供与型别无关的大小比较服务,例如: private IComparable confirm_comparable( object elem ) {
IComparable ic = elem as IComparable; if ( ic == null ){
string msg = \"Element type must support IComparable -- \" + elem.GetType().Name
+ \" does not currently do so!\"; throw new ArgumentException( msg ); }
return ic; }
5 / 70
全国计算机等级考试网上报名系统的设计与实现
我们可能这样调用上述的confirm_comparable(): public void insert( object elem ) {
// if this is the first element if ( m_root == null ){
confirm_comparable( elem ); m_elemType = elem.GetType(); m_root = new TreeNode( elem ); } else {
confirm_type( elem );
m_root.insert_value( elem ); } }
上述insert()只在插入第一个object时检测元素型别是否吻合约束条件。之后,它只是确认新的objects与最初object的型别是否相同。如果型别相同,就将元素插入树中,如下所示:
public void insert_value( object val ) {
// assumption is that BinaryTree has confirmed this ... IComparable ic = val as IComparable;
// OK: zero means the two objects are equal if ( ic.CompareTo( m_nval ) == 0 ){ m_occurs++; return;
}
// OK: less than; insert within left subtree if ( ic.CompareTo( m_nval ) < 0 ){ if ( m_lchild == null )
m_lchild = new TreeNode( val ); else m_lchild.insert_value( val ); }
else { // insert within right subtree if ( m_rchild == null )
m_rchild = new BTreeNode( val ); else m_rchild.insert_value( val ); } }
当我们以实际型别操纵一个object时,我们几乎可以忽略该型别实现了哪些
6 / 70
全国计算机等级考试网上报名系统的设计与实现
接口,然而,当我们操纵型别为object的物体时,找出接口和使用接口就变得重要起来,因为所有编译期型别信息都遗失了。当然我们也可以在运行期间查询object的真实型别——8.2节将介绍所谓的型别反射。 4.3 定义一个接口
在4.1节中,我们为业已存在的接口实现了一个新实体。4.2节比较简单,我们只不过是找出并使用某个型别的相关接口。本节我将引入一个接口定义式,它支持基于某个独特算法,生成并显示一个数列。下面是我打算支持的操作集(两个mestods、一个property、一个indexer):
* Generate_sequence(),生成元素的特定系列。 * Display(),输出所有元素。 * Length, 返回元素数目。
* Indexer,让用户得以反问特定元素。
Interface定义式都以关键字接口大头,后面紧跟一个名称。请记住.NET接口的名称习惯以大写字母’I’开头,后面紧跟首字母大写的名称。编译器并不强迫你遵守这个习惯。我把我的这个接口成为INumericSequence: public interface INumericSequence{}
如你所见,是的,空的接口是合法的。所以上一行表现的是一个完整的接口定义式。
接口允许定义的成员是class允许定义的成员的子集。接口只能声明methods、properties、indexers、event作为其成员,例如: public interface INumericSequence {
// a method
bool generate_sequence( int position );
// a set of overloaded methods void display();
void display( int first );
void display( int first, int last );
// a property
int Length { get; }
// a one-dimensional indexer int this[ int position ]{ get; }
7 / 70
全国计算机等级考试网上报名系统的设计与实现
}
接口的所有成员都暗自成为abstract。我们不能为它提供缺省实现,无论这份实现是多么平淡无奇,接口的成员也都暗自成为public,我们不能以关键字abstract或public来修改其中某个成员。
接口之内不能定义子集的数据成员,也不能定义构造函数或析构函数——由于缺乏数据成员,所以这两个特殊函数其实也就不需要了,此外接口不能声明static成员,由于const成员暗自也是static,所以接口也不允许声明const成员。操作符和static构造函数也不在允许之列。
接口可以继承自另一个接口,甚至继承多个接口: public interface INumericSequence : ICollection { ... } public interface INumericSequence
: ICollection, ICloneable { ... }
但接口不能显式继承自class或struct,所有接口都隐式继承最根源的object class。
4.3.1 实现我们自己的接口:概念验证
接口一旦被定义可我们如何检测其正确性呢?通常在定义接口之后,我们至少会提供一个实现品,作为概念验证或健全检测之用,以便确认接口的正确性。现在我提供一份实现品Fibonacci,用以测试我们的接口。
Fibonacci数列的头两个元素是1。将前两个元素相加就得到下一个元素。例如前8个Fibonacci元素为1,1,2,3,5,8,13,21.
现在我们应该从哪儿开始着手?
接口的实现得靠class或struct的继承才得以完成。Struct不适合本例,因为我不希望在应用程序中的那些对运行时间十分敏感的地点创建并操控一大堆Fibonacci objects。因此,我将Fibonacci 声明为class。由于我不希望它被继承,所以将它声明为sealed:
public sealed class Fibonacci : INumericSequence {}
然而上述控定义是非法的。从接口继承下来的class必须为每一个接口成员提供实现。即便遗漏一个成员没有实现,也将导致编译错误。除非实现接口的那个class本身也是个abstract class——如果真是这样,这个class可以将接口的成员函数声明为abstract。我将在4.5节详细解说这些概念和做法。
实现接口成员之前,我们必须先确定支持数列抽象性所必需的状态信息。此
8 / 70
全国计算机等级考试网上报名系统的设计与实现
外我们需要一个array来持有系列元素,还需要另外两个成员分别持有array的大小和容量。由于系列值固定不可变,我们只需要一个array就好。这个array和另两个成员都将声明为static。
接口的实现有两个要素:(1)为支持抽象性而必备的底层基础设施。;(2)为接口的每个成员提供定义。以下是Fibonacci class的设计骨架: public sealed class Fibonacci : INumericSequence {
// infrastructure to support sequence abstraction private static int [] m_elements; private static short m_count;
private static short m_capacity = 128;
// Fibonacci-specific methods:
// all for infrastructure supports static Fibonacci(){ ... }
private void check_pos( int pos ) { ... } private void grow_capacity() { ... }
// INumericSequence inherited members
public bool generate_sequence( int pos ) { ... }
public void display(){ ... }
public void display( int first ) { ... }
public void display( int first, int last ) { ... }
public int Length { get{ return m_count; }} public int this[ int position ] { ... } }
其中的indexer必须先行验证所取位置的有效性。我把这样的验证工作专门放入一个private成员函数check_pos()内。如果位置不合法,indexer就抛出一个异常,否则就返回位置减1处的元素: public int this[ int position ] {
get {
check_pos( position );
return m_elements[ position-1 ]; } }
由于C#的array索引从0开始,也就是说第一个元素的索引是0,所以我们
9 / 70
全国计算机等级考试网上报名系统的设计与实现
必须修正用户指定的位置。为什么不要求用户自己修正呢?这样的决定是否正确取决于我们对用户的假设。如果用户是软件研发人员,要求索引从0开始也许说得过去。然而不曾当过程序员的人,常常觉得第一个元素的位置是0的想法很不自然。现在将修正行为封装到class中,我们因而挑起了所有单字,全权负责,让代码用起来更安全,让用户更感觉舒适。
接下来,练习使用我们的实现品。首先直接产生一个Fibonacci class object;然后间接地将它视为一个一般性的INumericSequence object: public static void Main() {
// just some magic numbers – used as positions const int pos1 = 8, pos2 = 47;
// let's directly use interface through class object Fibonacci fib = new Fibonacci();
// invokes indexer;
// indexer invokes generate_sequence( pos1 ); int elem = fib[ pos1 ];
int length = fib.Length;
string msg = \"The length of the INumericSequence is \"; Console.WriteLine( msg + length.ToString() ); Console.WriteLine(
\"Element {0} of the Fibonacci Sequence is {1}\ pos1, elem ); fib.display();
// OK: let's now use interface generically INumericSequence ins = fib;
elem = ins[ pos2 ]; length = ins.Length;
Console.WriteLine( msg + length.ToString() ); Console.WriteLine(
\"Element {1} of the Fibonacci Sequence is {0}\ elem, pos2 );
ins.display( 44, 47 ); }
10 / 70
全国计算机等级考试网上报名系统的设计与实现
正如你所看到,我们的实现品稍微有瑕疵,这也正是为什么需要测试的原因,程序的输出证明确实存在着问题:
The length of the INumericSequence is 8 Element 8 of the Fibonacci Sequence is 21 Elements 1 to 8 of the Fibonacci Sequence: 1 1 2 3 5 8 13 21
The length of the INumericSequence is 47
Element 47 of the Fibonacci Sequence is -1323752223 Elements 44 to 47 of the Fibonacci Sequence:
701408733 1134903170 1836311903 -1323752223
怎么回事?程序竟然声称Fibonacci数列的第47号元素是-1323752223.这显然不正确。如果我们看看第44号元素至第47号元素的显示结果,也就很清楚究竟发生什么事了:
Elements 44 to 47 of the Fibonacci Sequence:
701408733 1134903170 1836311903 -1323752223
是的,我们将负责持有元素的m_elements的型别声明为int,不幸的是第47号Fibonacci元素太大,以至无法以int显示。其值溢出,影响了符号为,所以数值被不正确地显示为负数。如果要更良好地处理大型Fibonacci元素,我们必须重新定义m_elements,使它能够持有大型数值。
那一种型别才最适合呢?除了诺干整数型别,C#还提供有两种浮点型别以及28-digit精度的decimal型别。我将m_elements依次重声明uint、ulong、decimal、double;然后在第50个位置处发现,只有ulong、decimal、double屹立不动: Fibonacci Element #50 : (int) : -298632863 Fibonacci Element #50 : (uint) : 3996334433 Fibonacci Element #50 : (ulong) : 12586269025 Fibonacci Element #50 : (decimal) : 12586269025 Fibonacci Element #50 : (double) : 12586269025
到了第100位置处,只剩下decimal和double能够正确表示其值。然而其中的double开始丢失精度,这让人难以接受。只有decimal没有舍入。这表示Fibonacci系列元素的最佳选择是decimal型别:
Fibonacci Element #100 : (ulong) : 37367171
Fibonacci Element #100 : (decimal) : 354224848179261915075 Fibonacci Element #100 : (double) : 3.54224848179262E20
尽管如此,这还不是完整的解答。在139处位置处,decimal型别终于达到
11 / 70
全国计算机等级考试网上报名系统的设计与实现
了其28-digit精度上限:
Fibonacci Element #139 :(decimal): 5583911
Fibonacci Element #139 :(double) : 5.58406E28 如果尝试计算第140个位置,decimal会溢出并抛出以下异常: System.OverflowException:
Value is either too large or too small for a Decimal.
at System.Decimal.Add(System.Decimal, System.Decimal)
at System.Decimal.op_Addition(System.Decimal, System.Decimal) at Project1.Fibonacci.version_decimal(Int32) at Project1.MainObj.Main()
看来,如果使用C#预定义的算术型别,我们只能存储并显示前139个Fibonacci元素。除非我们决定实现出一个自定义的数值型别,用以支持巨大整数,否则我们必须定义出“用户所能申请的元素位置”上限。这个上限对所有Fibonacci数列都成立,因此我们在INumericSequence中加上这一限制的定义,如下:
public interface INumericSequence {
// the two new properties int Length { get; } int MaxPosition { get; } // ... rest the same ... }
public sealed class Fibonacci : INumericSequence {
// infrastructure to support sequence abstraction
private static int [] m_elements = new int[ m_maxpos ]; private static short m_count;
private const short m_maxpos = 128;
public int MaxPosition { get{ return m_maxpos; }}
// ... rest the same, except no longer need to grow array }
这意味着尽管合法的Fibonacci元素位置有无限多个,但我们无法轻松地全部予以支持。事实上我们无法全部支持。此外用户也许会指定一个非法位置——任何小于或等于0的位置都是不合法的,我们该如何处理这两种无效状态?C#和.NET程序设计的习惯是,通过异常的引发来报告程序中的不正常情况。
12 / 70
全国计算机等级考试网上报名系统的设计与实现
但是抛出哪个异常呢?遇到无效位置和不被支持的位置时,是否应该抛出不同的异常?答案并无唯一性,谁来决定呢?如果每个接口的实现可以自行决定抛出什么异常,那就几乎不可能安全地以一般化方式对接口进行编程。举个例子,如果要写出以下代码:
INumericSequence ins = o as INumericSequence; if ( ins != null )
elem = ins[ pos2 ];
我们应当确知:每个indexer实现品都以完全相同的方式回报无效位置。
这意味着接口定义式必须决定在什么条件下抛出异常以及抛出哪一种异常。不幸的是我们只能通过文档加以说明。C#无法直接将成员和其所能抛出的异常关联起来。
13 / 70
因篇幅问题不能全部显示,请点此查看更多更全内容