实验一:生命周期模型&可行性研究
1.假设你被任命为一家软件公司的项目负责人,你的工作是管理该公司已被广泛应用的文字处理软件新版本的开发。由于市场竞争激烈,公司规定了严格的完成期限并且已对外公布。你打算采用哪种软件生命周期模型?为什么?
2.利用课本知识对以下问题进行可行性研究:
假设你在某公司工作,负责该公司信息系统的建设与维护。财务长请你研究用公司拥有的计算机生成工资明细表和各种财务报表的可能性。
请详细描述你用可行性研究方法分析上述问题的过程,要求:
(1)复习课本可行性研究的内容,系统流程图及DFD的基本元素及绘制原则和步骤。
(2)根据可行性研究的步骤进行上述问题分析。
(3)弹性作业,可以根据自己的想象或认识对问题域做一定的扩展。
步骤提示:
A.明确问题定义,澄清系统规模和目标,输出关于系统规模和目标的报告书。(可以通过对用户进行询问,财务长为什么想研究在自己的计算机上实现工资支付系统的可能性?询问后得知,随着公司规模的扩大,工作量也越来越大,每个月都需要2名会计紧张工作一个月才能完成,效率低,成本高,每名会计月工资在7500元)
系统规模和目标的报告书模板:
关于系统规模和目标的报告书 2019.03.10
项目名称:
问题:
项目目标:
项目规模:
初步设想:
可行性研究:
B.研究现有系统(现有系统为人工处理,需要对会计等人员进行访问,了解详细过程,并用系统流程图表示)
详细过程:每个月HR会把每位员工的月绩效考核成绩汇总登记在绩效表上,交给财务科,财务科根据每位员工的绩效、合同月薪及职级,计算其工资及岗位津贴,再根据工资总额计算应缴纳个人所得税、住房公积金、保险费,最终计算出实发工资,并打印出工资明细表给员工,同时生成一张工资报表报送银行,由银行把钱打到每名员工的银行卡上。
…
C.导出新系统的高层逻辑模型(绘制新系统DFD图)
3.上周课件里的练习题:
考虑一个修改磁带上主文件的系统。文件管理员把修改信息穿孔在卡片上,系统读入穿孔卡片上的信息并按照记录号把修改信息顺序排列好。然后系统逐个读入主文件上的记录,根据记录上的校验码核对每个读入的记录,丢掉出错的记录,按照修改信息修改余下的记录,产生的新文件存储在磁盘上。最后系统根据新文件及修改信息输出一份修改报告供文件管理员参阅。(基本系统模型+功能级数据流图)
实验二:产品原型
构建一APP原型,包括两个Activity:登陆页面和首页,类似如下形式,内容不限。
实验三 形式化说明技术
- 问题描述:
保险箱带复合密码锁,锁有3个位置…(规则同课本4.2节内容)。
请用C语言实现此状态机的代码。
- 用IBM Ration Rose画出该状态图。
(安装IBM Rational Rose v7.0版本,虚拟光驱安装,如果导入license后,打开显示license error,修改系统时间至2020以前,再次导入license即可)
(也可用其他软件,如Visio、Enterprise Architec等,不过UML支持性能最好的还是Rational)
一个浮点二进制数的构成是:一个可选的符号(+或-),后跟一个或多个二进制位,再跟上一个字符E,再加上另一个可选符号(+或-)及一个或多个二进制位。例如,下列的字符串都是浮点二进制数:
110101E-101
-100111E11101
+1E0
更形式化地,浮点二进制数定义如下:
〈floatingpoint binary〉∷=[〈sign〉]〈bitstring〉E[〈sign〉]〈bitstring〉
〈sign〉∷=+|-
〈bitstring〉∷=〈bit〉[〈bitstring〉]
〈bit〉∷=0|1
其中,符号∷=表示定义为;符号[…]表示可选项;符号a|b表示a或b。
假设有这样一个有穷状态机:以一串字符为输入,判断字符串中是否含有合法的浮点二进制数。
实验四 需求描述和模块耦合
- 请为某仓库的管理系统设计一个ER模型。
该仓库主要管理零件(零件编号,零件名称,数量)的订购和供应等事项。仓库向工程项目供应零件(供应时需明确供应零件的数量),并且根据需要向供应商订购零件(订货单要指定订货零件订货数量)。
- 在一非空整数表中查找某个给定整数,找到则输出1,没找到则输出0并将添加至表中。用Z语言写出查表操作的规格说明。
3.阅读下面的程序
判断模块“main”和模块“ModifyDate”及“PutConstellation”之间分别是什么类型的耦合?说明理由,并考虑如何修改。
typedef struct{
int year;
int month;
int day;
}Date;
typedef struct
{
long int id;
char name[32];
char address[64];
Date birthday; //默认初始输入为阴历
}Student;
void ModifyDate(Student *pStu)
{
// 调用DateTransform
//…
}
void PutConstellation(Student *pStu) //根据阳历日期计算及输出星座
{
// 计算星座
// 输出星座
}
void main()
{
Student stu[100];
// 输入若干学生的数据
// …
odifyDate(stu);
PutConstellation(stu);
}
Date DateTransform(Date dataTmp) //将原来的阴历日期修改为阳历日期
{
// 实现省略
}
4.阅读下面的程序
说明整个程序中存在哪些耦合?
static bool Signal;
void AdultOrNot(int age)
{
if (age > 18)
{
Signal = 1;
} else {
Signal = 0;
}
}
void WineOrNot()
{
if (Signal == 1)
{
printf("%s\n", “您已到达法定饮酒年龄!”);
} else {
printf("%s\n", "您未到达法定饮酒年龄!");
}
}
int main()
{
int Age = 0;
printf("%s", “请输入您的年龄:”);
scanf("%d", &Age);
AdultOrNot(Age);
WineOrNot();
}
实验五:模块独立性
-
- 阅读下面的程序,判断模块“PutConstellation”是什么类型的内聚?
typedef struct{
int year;
int month;
int day;
}Date;
typedef struct
{
long int id;
char name[32];
char address[64];
Date birthday; //默认初始输入为阴历
}Student;
void ModifyDate(Student *pStu)
{
// 调用DateTransform
//…
}
void PutConstellation(Student *pStu) //根据阳历日期计算及输出星座
{
// 计算星座
// 输出星座
}
void main()
{
Student stu[100];
// 输入若干学生的数据
// …
ModifyDate(stu);
PutConstellation(stu);
}
Date DateTransform(Date dataTmp) //将原来的阴历日期修改为阳历日期
{
// 实现省略
}
解:顺序内聚
- 阅读下面的程序
(1)对于模块AdultOrNot而言,是否满足“作用域在控制域范围内”的启发规则?为什么?
(2)描述此程序结构图。
(3)调整程序结构,使之更好满足独立性要求。
//根据年龄判断是否大于18岁,然后根据是否满十八岁判断是否到达法定饮酒年龄
static bool Signal;
void AdultOrNot(int age)
{
if (age > 18)
{
Signal = 1;
} else {
Signal = 0;
}
}
void WineOrNot()
{
if (Signal == 1)
{
printf("%s\n", “您已到达法定饮酒年龄!”);
} else {
printf("%s\n", "您未到达法定饮酒年龄!");
}
}
int main()
{
int Age = 0;
printf("%s", “请输入您的年龄:”);
scanf("%d", &Age);
AdultOrNot(Age);
WineOrNot();
}
解:
- 下面的模块为某系统MFC对话框初始化代码,判断该模块内聚类型。
BOOL CSuperresolutionDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
ShowWindow(SW_SHOW);
// TODO: 在此添加额外的初始化代码
// 设置工具栏button的icon
HICON hIcon=AfxGetApp()->LoadIcon(IDI_ZOOMIN);
((CButton*)GetDlgItem(IDC_BUTZOOMIN))->SetIcon(hIcon);
hIcon=AfxGetApp()->LoadIcon(IDI_ZOOMOUT);
((CButton*)GetDlgItem(IDC_BUTZOOMOUT))->SetIcon(hIcon);
hIcon=AfxGetApp()->LoadIcon(IDI_HELP);
((CButton*)GetDlgItem(IDC_BUTHELP))->SetIcon(hIcon);
hIcon=AfxGetApp()->LoadIcon(IDI_SELECT);
((CButton*)GetDlgItem(IDC_BUTSELECT))->SetIcon(hIcon);
// 设置工具栏的按钮提示
m_pToolTip.Create(this);
m_pToolTip.AddTool( GetDlgItem(IDC_BUTSELECT), _T("选择图像局部区域进行重建") );
m_pToolTip.AddTool( GetDlgItem(IDC_BUTZOOMIN), _T("放大图像") );
m_pToolTip.AddTool( GetDlgItem(IDC_BUTZOOMOUT), _T("缩小图像") );
m_pToolTip.AddTool( GetDlgItem(IDC_BUTHELP), _T("Version:1.1 beta. \nCopyrighted by Tianfeng Hou.") );
m_pToolTip.SetDelayTime(200); //设置延迟
m_pToolTip.SetTipTextColor( RGB(0,0,255) ); //设置提示文本的颜色
m_pToolTip.SetTipBkColor( RGB(235,235,235)); //设置提示框的背景颜色
m_pToolTip.Activate(TRUE); //设置是否启用提示
// 设置信息提示栏
GetDlgItem(IDC_CAPTION)->SetWindowText(_T("信息提示栏.\t欢迎反馈bug: h_tf@qq.com"));
// 设置左侧按钮,顶部工具按钮,底部按钮,右侧列表框的状态
EnableControl(FALSE, 12, IDC_BUTCLEAR, IDC_BUTDELETE,
IDC_BUTSELECT, IDC_BUTZOOMIN, IDC_BUTZOOMOUT,
IDC_BUTORIGINAL, IDC_BUTRESULT, IDC_BUTCONTRAST, IDC_BUTSAVE,
IDC_PLAY, IDC_PAUSE, IDC_STOP);
// 设置表单
m_sheet.AddPage(_T("滤波器组"), &m_page1, IDD_PROP1);
m_sheet.AddPage(_T("超分辨率"), &m_page2, IDD_PROP2);
m_sheet.Show();
m_sheet.SetBkgndColor(RGB(123,12,143));
m_sheet.EnableDraw(BTC_ALL);
CEnTabCtrl::EnableCustomLook(TRUE,ETC_FLAT|ETC_SELECTION);
m_sheet.Invalidate();
//SetWindowPos(NULL,200,70,0,0,SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
解:时间内聚
- 分析下面的程序,评价内聚耦合如何,若有不当,如何修改?
class Teacher{
private String id;
public void setId(String id)
{
this.id=id;
}
public String getId()
{
return id;
}
}
class Student{
private String id;
public void setId(String id)
{
this.id=id;
}
public String getId()
{
return id;
}
}
class StudentManage{
publicList<Student> getAllStudent()
{
List<Student> list=new ArrayList<Student>();
for (int i=0;i<100;i++)
{
Student student=new Student();
student.setId("学生学号是"+i);
list.add(student);
}
return list;
}
}
class TeacherManage
{
publicList<Teacher> getAllTeacher()
{
List<Teacher> list=new ArrayList<Teacher>();
for (inti=0;i<100;i++)
{
Teacher teacher =new Teacher();
teacher.setId("老师编号"+i);
list.add(teacher);
}
return list;
}
public void printAllPerson(StudentManage studentmanager)
{
List<Student>list1=studentmanager.getAllStudent();
for (Student s:list1)
{
System.out.println(s.getId());
}
List<Teacher>list2=this.getAllTeacher();
for (Teacher t:list2)
{
System.out.println(t.getId());
}
}
}
public classClient {
public static void main(String[] args) {
TeacherManage tm=new TeacherManage();
tm.printAllPerson(new StudentManage());
}
}
实验六:面向数据流的设计方法
- 按照面向数据流的设计步骤将下面银行计算机储蓄系统的DFD映射为结构图
- 按照面向数据流的设计步骤将下面文件修改系统的DFD映射为结构图
- 问题域描述:
某医院打算开发一套以计算机为中心的患者监护系统。该系统的基本要求是:系统随时接收每个病人(姓名、住址、电话号码、住院号)的生理信号(脉搏、体温、血压、心电图等),定时记录病人情况以形成患者日志,当某个病人的生理信号超出医生规定的安全范围时向值班护士发出警告信息,护士(姓名、科室、工号)对警告信息进行测量确认,如果属于危机级别,则呼叫主治医生(姓名、科室、职级),由主治医生对病人实施救助措施,并记录救助信息(救助时间、症状、措施、结果)。此外,医生与护士在需要时还可以要求系统印出某个指定病人的病情报告。
请将其转换为关系模型;
实验七:过程设计
- 观察如下流程图,回答:
(1)为什么它是非结构化的?
(2)设计两种等价的结构化程序(一种使用附加的标志变量flag,一种不使用,设计结果用N-S图表示)。
解:(1)因为有一个入口两个出口,所以为非结构化
(2)
2. 阅读下面的C程序,
(1) 描绘calGaussCoef模块灰色部分代码段的流图,用McCabe方法计算环形复杂度;
(2) 用Halstead方法计算calGaussCoef模块灰色部分代码段的程序长度、估计长度,并预测错误数。
#include "stdio.h"
#include "math.h"
#include <iostream>
#include <time.h>
#define SUPPORT_SIZE 2 // 高斯滤波窗口半径
#define IM_WIDTH 1440 // 输入图像宽和高
#define IM_HEIGHT 1080
// 计算高斯系数
void calGaussCoef(double *pGaussCoef)
{
int i, j, k;
int wlen = (SUPPORT_SIZE<<1) + 1;
double sum = 0;
if(pGaussCoef)
{
for(i = -SUPPORT_SIZE; i <= SUPPORT_SIZE; i++)
{
for(j = -SUPPORT_SIZE; j <= SUPPORT_SIZE; j++)
{
//计算高斯系数,2.71828为自然数e
pGaussCoef[ (i+SUPPORT_SIZE)*wlen + j+SUPPORT_SIZE ] = pow( 2.71828, (-double(i*i + j*j)/25) );
}
}
for(k = 0; k < wlen*wlen; k++)
{
sum += pGaussCoef[k];
}
for(k = 0; k < wlen*wlen; k++) //进行归一化处理
{
pGaussCoef[k] /= sum;
}
}
}
// 2维卷积函数,实现2维图像高斯滤波
// pGaussCoef为高斯系数
// pSrcImg为原始图像
// pDstImg为滤波后图像
// height:图像高度
// width:图像宽度
// supportSize:高斯滤波窗口半径,直径为2*supportSize + 1
void conv2D(double *pGaussCoef, unsigned char *pSrcImg, unsigned char *pDstImg, int height, int width, int supportSize)
{
int i, j;
int m, n;
int indexI, indexG;
int sw = supportSize;
int slen = sw*2 + 1;
double sum;
double *pTemp = NULL;
pTemp = new double[height*width];
for(i = 0; i < height*width; i++)
{
pTemp[i] = (double)pSrcImg[i];
}
for(i = sw; i < height - sw; i++)
{
for(j = sw; j < width - sw; j++)
{
sum = 0;
calGaussCoef(pGaussCoef);
for(m = -sw; m <= sw; m++)
{
for(n = -sw; n <= sw; n++)
{
indexI = (i+m)*width + j+n;
indexG = (m+sw)*slen + n+sw;
sum += pSrcImg[indexI] * pGaussCoef[indexG];
}
}
pDstImg[i*width + j] = (unsigned char)(sum);
}
}
}
void main()
{
int wlen, imLen;
time_t start, end;
double *pGaussCoef = NULL;
unsigned char *pSrc = NULL, *pDst = NULL;
unsigned char buffer[1078]; //定义BMP图像文件头部缓冲区
FILE *fin, *fout;
if( !(fin=fopen("in.bmp","rb")) ) //打开原始输入图像
{
printf("Open file %s error!\n","in.bmp");
exit(1);
}
if( !(fout=fopen("out.bmp","wb")) ) //创建滤波后输出图像
{
printf("Open file %s error!\n","out.bmp");
exit(1);
}
wlen = SUPPORT_SIZE * 2 + 1;
imLen = IM_WIDTH * IM_HEIGHT;
pGaussCoef = new double[wlen*wlen];
pSrc = new unsigned char[IM_WIDTH*IM_HEIGHT];
pDst = new unsigned char[IM_WIDTH*IM_HEIGHT];
fread(buffer, 1, 1078, fin); //读取1078字节BMP图像文件头信息
fread(pSrc, sizeof(unsigned char), imLen, fin); //从输入文件读入图像数据
start = clock();
conv2D(pGaussCoef, pSrc, pDst, IM_HEIGHT, IM_WIDTH, SUPPORT_SIZE); //执行滤波
end = clock();
printf("running time is %d\n", end - start);
fwrite(buffer, sizeof(unsigned char), 1078, fout);
fwrite(pDst, sizeof(unsigned char), imLen, fout); //将滤波结果写到新文件
delete[] pGaussCoef;
delete[] pSrc;
delete[] pDst;
fclose(fin);
fclose(fout);
}
for(k = 0; k < wlen*wlen; k++)
{
sum += pGaussCoef[k];
}
for(k = 0; k < wlen*wlen; k++) //进行归一化处理
{
pGaussCoef[k] /= sum;
}
(1)
(2)
运算符出现的总次数N1=14
操作数出现的总次数N2=18
所以,程序长度为N=N1+N2=14+18=32
使用不同运算符的个数:n1=8
使用不同操作符的个数:n2=5
所以,预测程序长度为H=n1 log2 n1+n2 log2 n2=8log2 8+5log2 5=35.6095
预测程序中的错误E=Nlog2 (n1+n2)/3000=0.04