to 晨晨
隔了很长时间才继续写感想,过去的思路都中断了,现在重新整理,其实
在这个过程中,我也将自己的整体思路作了一些总结,自己感到有不少提
高,谢谢你的例子。
第一:关于需求分析的可行性分析部分
我觉得你的图二有些问题,不过首先说一个前提,这是Delphi的观念,和
MS的观念不一定一样(我发现MS,Borland,IBM,SUN等关于一些流行的概念
,各有各的说法)。
具体原因如下:
1。应用服务器Application Server在Delphi指的是使用TRemoteDataModule
(也可以不是)包装的对象,它可以是一般的COM对象(支持简单的_AddRef等
接口),也可以是DCOM/COM+对象,可以分布在MTS/COM+管理。
所以觉得有些不对劲,但是好像又没有什么问题!
关于C/S,B/S,2-tier,3-tier,multi-tier的叙述组织上好像有些需要调整。
我理解你的谈论是关于实现的架构问题,你的结论是
“采用微软公司所推出的Web分布式多层应用程序结构,并且数据使用XML表
示”
这没有什么不可以,我的感觉应当放在后面,也就是设计的时候说。这个时
候你的问题是可行性分析,该说一些技术可行性,经济可行性。。。,我的
感觉删掉为好,这个小问题犯不着扣个大帽子。
我的只是来自于RUP,可能有很多不一样和不对的地方,还请包涵。
第二:用例模型
我觉得这才是需求分析的主要内容。
你将学生,教师,管理员继承用户,这种思想我觉得是一种解决方案,但是
我觉得将用例:
1。登录
2。修改个人资料
做成用户的用例,而学生,教师,管理员继承这些用例,可能更加能够贯彻你
的初衷,否则删掉用户这个Actor也没有什么不对。同时这样也相对简洁。
管理员的用例
1。管理学生账号
2。管理老师账号
或许可以合并成“管理账号”,内容应当差不多的。另外管理员自己的账号如何
管理呢?过去的用例模型中没有谈论。
我觉得你的账号管理没有说清楚。
我的理解账号管理有这样几种模式:
1。类似于e-mail账号的管理,用户可以申请账号,成功后也可以修改个人资料,
管理员可以审核申请,也可以直接添加,修改,删除账号。
2。完全自由的模式,用户可以直接添加,修改,删除自己的账号,管理员这个
角色便不需要
3。集中管理的模式,用户只能修改个人资料,不能注册,也不能删除账号,或者
采用非计算机手段完成。
我觉得你的账号管理模式采用第一类比较好。不过它的审核有些问题。我假设系
统
仅仅有一个管理员,名字为Administrator,密码可变,名称不可变,账号不可删
除。和你的有些相似。
用例模型我的最后修改如下
1。Actor列表
用户
老师
学生
管理员
2。Actor之间关系
用户
/ | /
学生 老师 管理员
3。核心用例列表
用户
-注册
-修改个人资料
-登录
学生
-考试
老师
-试题库维护
管理员
-注册审核
-账号维护(包括增加,删除)
4。支持用例列表
学生
-查询个人考试历史情况
老师
-查询考试情况
还可以加上一些另外一些侧面的视图,比如
1。安全用例列表
2。账号管理相关用例列表
。。。
我就不举了
第三。类图
类图一描述用户之间的关系,我的方案是
---> 用户
| / | /
| / | /
管理员 学生 老师
即
1。管理员,学生,老师继承用户
2。管理员管理用户,是1对多的关系
这是一个关系环,和Composite Pattern类似
类图二描述试题和用户之间的关系,我认为首先应当谈论试题本身
,也就是试题,试卷的问题。
一份试卷有多个试题构成,每个试题有不同的类型和内容,它也有
答案。这里的试题一开始仅仅有选择题,我们可以考虑到扩展,这
样设计
试卷
|
试题
/ | /
选择题 填空题 ...
老师和试卷的关系是1对多的维护关系,学生和试卷的关系是1对多的
考试关系。即
老师------>试卷<-----学生
到现在为止,我认为仍然在于分析阶段,只有一些核心类,一些类的
属性和方法可以得到,我觉得到设计的时候再添加设计类,然后再设
计它们的具体属性方法等。
下面开始设计。
第四,架构。
我觉得这里应当描述你的分层架构:
client:采用Browser
Web Server:使用ASP技术编写服务器端程序,实现动态页面。
Application Server:使用Delphi编写Business Services组件(满足MTS/
COM+)。
Data Server:使用Sql Server存储数据
这里的内容涉及到了实现,比如c/s,b/s之类,你可以放在后面说。我觉得
只需要描述层而已。
你也可以加一些中间层,比如数据访问层或者其他中间件层等等。
第五,数据库设计
也就是Data Server层的设计
1。用户,学生,老师,管理员的关系映射
方案有很多,采用你的方案也不错,分成三个表,共同属性为:
编号
姓名
密码
e-mail地址
它属于用户类的属性的映射,隐藏的属性为用户角色类型(即学生,
老师,管理员等角色)
学生独有的属性为学号,性别等等
老师和管理员可以没有独有的属性(我觉得老师不应当包括科目属性,
它应当是试卷的属性)
另外,编号可以是三个表唯一的,也可以分开设计,具体的就比较复杂
,可以简化。
和你的大同小异.
2。试题和试卷的映射
试卷表的结构如下
编号
科目
选择题的结构如下:
编号
试卷编号
问题
选项1
选项2
选项3
选项4
答案
(注意,这里有个假设,即一道试题仅仅属于一套试卷。这是简化的做法
,如果采用其他假设,便相当复杂。)
我没有看清楚你的做法具体情况。
3。老师和试卷关系的映射
试卷表添加一个出题老师编号表达它们之间的1对多的关系。和你的一样。
4。学生和试卷之间的关系的映射
它们之间是多对多的关系,即1个学生可以多次作同一套题目,一套试卷可以
有多个学生作。应当设计一个二元关系类:考试类和对应的表考试表。结构
可以简化如下:
编号
日期
学生编号
谁卷编号
分数
不过你的功能是同一套题目学生仅仅能做一次,即为一对多关系,在这个前提
下,你的设计也是对的。
整体说来,我觉得我的这种映射方式比你的清晰,和前面的类图一脉相承。
另外,我觉得花费大量的篇幅表达生成的数据库物理视图,过于浪费。
第六。业务逻辑层的设计
你的组件内容在前面的类图中就已经给出,但是我觉得在设计的时候最终得到
为好。因为这个时候可以专门考虑一些问题。
你的组件有:
1。学生
2。老师
3。管理员
4。密码验证
这是实现的形式,即组件视图。这里应当考虑具体的类,组件视图应当放在后
面。
这里的类有
用户
学生
管理员
老师
试卷
试题
选择题
它们属性和方法的捕作,可以采用用例实现的方法(这是RUP里面的方法),在
分析的时候,用例模型中也应当有初步的粗糙的实现过程(即动态模型,使用顺
序图,活动图等表达的),我在前面没有谈到它,你则有。我是因为它那个时候
表达的不可能清楚,所以略去。这里必须详细的说明。
1。“用户登录”用例:
你的是学生和老师登录,然后返回确认,我觉得有多种设计方案。
1。设计一个函数Login
Function Login(AstrUserName,AstrUserPassword):TUser
传递用户名和密码,如果通过返回这个用户,TUser是TStudent,TTeacher,
TAdministator的父类,用它来做转换。如果没有通过,则返回NULL即可。
2。也可以设计成
Function Login(AstrUserName,AstrUserPassword,var AUser:TUser):Boolean
3。也可以将Login作为TUser的静态方法
Function Login(AstrUserName,AstrUserPassword):Boolean
甚至一般方法(区别在于调用)
4。将Login作为TUser的方法,TStudent,TTeacher,TAdministator进行重载。
还有其它的设计,我选择第四种方法。
2。“用户注册”和“用户个人资料修改”
同样和用户登录一样处理
3。“考试”用例
这个比较复杂。你的处理顺序是
1。首先学生申请,系统校验学生的身份(那个类处理?你的是学生类,有些
问题)
2。向试卷类申请试卷,试卷创建多个试题,返回一套试卷(也就是Create)
3。用户作试题,也就是向试卷中添加修改删除答案
4。用户提交试卷
5。试卷批改,返回成绩,
6。保存此次纪录
在我而言,这里的学生申请考试似乎有些多余,不过你的规则是学生仅仅只能
考一次试(对于某一门考试),这样也可以。关键在于谁来判断。你的控制逻
辑没有交待清楚,就由学生类自己判断吧!
另外有一个问题是试卷试题对于学生和老师具有不同的含义:
对于老师而言:
试卷:老师出的,学生要考试的内容,没有学生名和成绩等等
试题:试卷的内容
对于学生而言:
试卷则是他所作的一份具体的试卷,中间包括具体的时间,学生名和成绩等等
前面的试卷应当是它的一部分,所以设计成考试类。
试题同样要增加一个是学生具体的所作答案。按理说,应当设计对应的答案类
选择题答案类和其他题型的答案类,这样试题类和具体题型的试题类可以独立
处理,但是过于复杂。
它们的关系可以如下:
考试类
/ | /
学生类 试卷类 答案集类
| |
试题类 答案类
/ | /
选择题类 选择题答案类
也可以设计成一个专门的考试试卷类,继承自试卷类,设计一个考试试题类,
继承自试题类,设计一个考试选择题类,继承自选择题类。。。
或者简单的以学生的试卷类和试题类等的内容为准,只是老师用的时候不管
那些多余的属性。这样简单,但是扩展性。。。
也可以断掉之间的关系,即
将试卷类装饰为考试类?
将试题类装饰为考试试题类
将选择题类装饰为考试选择题类
。。。
这样类的关系如下:
考试类
/ |
学生类 考试试题类
/ |
考试选择题类
我采用最后一种方式.
由上可以得到:
考试类TExamine
属性有:
ProblemCount
Student
Date
Score
方法有:
procedure Create(AStudent:TStudent;
AintExamNo:integer);
// 创建一份试卷
procdure Submit;
// 交卷
procedure Save;
// 保存考试纪录
function GetExamProblem(AintIndex:integer):TExamProblem;
考试试题类TExamProblem
比起试题TProblem而言多了一个属性Answer,用它来设置和提取答案。
考试选择题类TExamSelectProbel
具体实现Answer属性(也就是使用A,B,C,D表达)
学生类TStudent
function ValidExam(AstrSubject:string):boolean;
// 校验考试资格
function GetExamNo:integer;
// 获得考试的试卷号
4。“试题库维护”用例
实际上采用b/s方式进行大量输入的工作,我觉得不适合,但也无所谓。
你的顺序图中很简单。它无非是试卷中的试题的增删改而已。
老师类
包含一个属性即他所出的试卷集合Problems[]表示,采用类似于数据库的
接口,即
Append/Insert
Edit
Delete
Problems[index]
Count
First
Prior
Next
Last
MoveBy
。。。
可能好一些。
试卷类TProblems
它是试题的容器类,属性有
Teacher(老师,类型为TTeacher)
Date(建立日期)
Subject(科目)
ProblemCount
等,也可以采用类似于数据库的接口
但是它的问题在于存在多种不同的题型。逻辑会复杂一些。
试题类TProblem
这是一个抽象的类,相当于接口,
选择题类TSelectProblem
属性有:
Title
SelectOption1
SelectOption2
SelectOption3
SelectOption4
ScoreValue(分值,采用固定分值,是为了简化)
StandardAnswer(标准答案)
实际上,我们采用的这种类似于数据库接口的设计相当低层,实现的时
候,可以直接使用数据集等表达。
但是有些时候我们需要比较高层的接口,则可以将它们包装成你需要的
方式。
其它的用例就不谈了。我觉得自己的设计相当混乱,我感觉是自己对于
层次的划分没有掌握好,其中的折衷没有能力计算好,所以得到的结果
不是很清楚,显得繁琐。
我也知道有些设计比我的设计更加简单,但是我觉得它并非是多层的应
用,它将很多细节简单化,并没有体现到重用等的设计目的。两层的系
统就是逻辑简单,但是设计。。。
总而言之,自己的设计并不怎么样。
第六。界面设计
不谈。应当不是很难。
下面开始谈实现
第七,实现架构
你的data server采用SQL Server2000实现
各个类,也就是Web Server Applicaion,即Web组件实现采用Delphi的
Web技术实现,中间的数据访问采用ADO实现,使用XML表达数据。
划分成四个MTS/COM+组件
Web Server端程序采用ASP等技术实现.
另外说一下,你的做法和Delphi自己的做法不一样,不过Delphi的做法大家
本来用得不多。
第八,实现代码
有些问题,但是无伤大雅
第九,测试
没有
第十,部署。
不谈。