Java项目开发全流程实践

文章导读

【项目遵循需求分析、程序设计、编码、测试、运行标准开发过程, 从分析项目问题入手,提出解决方案,应用对象建模工具UML设计系统,依据设计文档进行编码。】

问题描述:实现一个简单的四则运算器。满足用户在Windows命令行窗口可以进行简单四则运算的要求。

1、四则运算具体功能要求:

(1)实现带单个运算符表达式的计算;

(2)用户可以重复输入表达式进行计算;

(3)输入quit退出程序;

(4)显示程序帮助内容。

2、角色划分与用例描述

角色是与程序相关的人和物,是指程序以外的,在使用程序或与程序交互中所扮演的角色。例如:使用程序的人、程序运行所依赖的环境等,本节主要讨论程序与人相关的角色。

本程序涉及的角色只有一个,就是程序的使用者,使用者输入算式,程序给出算式结果;使用者输入quit命令,程序退出;当使用者不熟悉该程序如何使用时,使用者可以查看程序给出的帮助说明。

本程序采用用例图对角色功能进行描述,通过用例图对功能需求进行分析和整理,绘制用例图的过程就是程序建模过程,建立的模型就是用例模型。

通过角色分析可知,程序使用者有三个用例模型,分别是输入算式、退出程序、查看帮助。

3、用例图

在一个用例图中通常有三种元素:参与者(Actor)、用例(Use Case)与程序边界(Boundary)。用例描述的是程序为用户提供的功能,也就是程序能为用户做什么,图例符号为一个椭圆;参与者是表1中划分的角色,也就是程序的使用者,图例符号为一个小人儿;最后是程序边界,程序边界描述了程序本身实现的功能与外部交互的边界,例如:参与者在程序边界之外,用例在程序边界之内,图例符号为一个方框。

(1)算式计算用例图(U001)

算式计算用例包含5个子用例,其中<输入算式>用例、<算式求解>用例、<查看答案>用例和使用者有交互行为,<计算算式>用例和<扫描算式>用例为内部用例,由<算式求解>用例调用并使用,<扫描算式>用例扫描算式,如果发现算式错误,由算式求解返回错误给使用者。

(2)退出程序用例图(U002)

该用例包含两个子用例,用例<输入判断>用于判断用户输入的字符串,如果字符串等于“quit”,调用<退出程序>用例退出程序。

(3)查看帮助用例图(U003)

该用例包含两个子用例,用例<输入判断>用于判断用户输入的字符串,如果字符串等于“help”,调用<输出帮助内容>用例显示帮助内容。

4、根据需求设计程序

前面需求分析阶段给出了角色、用例和业务流程。设计阶段需要将需求阶段给出的角色、用例和业务流程模型映射到能够被编程语言识别和描述的对象、对象功能和对象行为模型,设计阶段用到的UML模型有类图、活动图、时序图、状态图、部署图、伪代码。

设计阶段需要针对需求阶段给出的角色与用例,规划出对象类。在UML设计模型中,一般将对象类分为边界类、控制类和实体类。边界类主要用于描述外部参与者与程序之间的交互。例如:角色“程序使用者”同四则运算器的交互行为,其交互行为有“程序使用者”输入算式、查看帮助、退出程序等;控制类用于描述程序的控制流程。例如:四则运算器开始运行后,需要持续等待用户输入命令或算式,根据用户输入的内容选择不同的流程;实体类一般用于事物、人员或者一些现实生活中的对象,该类对象有存储数据的要求。例如:如果四则运算器要求区分角色“程序使用者”并存储角色信息时,就需要为角色“程序使用者”建立实体类,以便程序存储每个“程序使用者”的信息。

四则运算器的角色“程序使用者”并没有存储其信息的要求,因此无需为该角色建立实体类。与该角色相关的有三个用例,分别是<输入算式>用例、<算式求解>用例和<查看答案>用例,该三个用例都有流程控制和外部交互需求,故分别需要为这三个用例建立控制类和边界类。从设计实用性、编程效率方面考虑,可以将控制类和边界类合并为一个控制类;但从可维护性和扩展性上考虑,分开设计有利于代码结构清晰、并易于扩展四则运算器的功能。具体选择什么样的设计模式,需要根据程序(系统)所处的环境、技术、资源来决定,例如:一个程序(系统)在交付日期已经确定,项目进度紧张,而技术和人力资源又出现问题的情况下,应以设计实用性、编程效率方面考虑,反之则应从可维护性和扩展性上考虑。本节主要用于说明如何根据需求分析归纳类对象,从简单易懂考虑,采用合并设计原则。

类名命名为“Arithmetic”,类名确定后,需要根据用例及业务流程图归纳类的属性和方法。

从前面的用例图和业务流程图分析可知,程序主要涉及到算式、帮助内容、错误信息三部分信息,这三部分信息都有被程序修改内容和获取内容的需要,因此可以归纳为“Arithmetic”类的属性。类的属性不同于类的成员变量,类的属性可以通过get方法获取属性内容,通过set方法设置属性内容。

一般来说,用例图中的子用例都可以归纳为类的方法。例如:用例<算式计算>的子用例<<输入算式>>、<<计算算式>>、<<扫描算式>>等都可以归纳为类的方法。

图4 Arithmetic类图

 

类图说明

类图设计完成后,根据设计的需要,可能还需要设计活动图、时序图、状态图、部署图等。其多用于复杂的程序(系统)进一步理顺业务活动、流程、事件、部署等设计需要。本程序结构简单,无需再设计活动图,类图设计完成后,基本就可以进入编码了。

程序流程控制功能

程序启动运行后,首先显示帮助内容,向用户提示程序的使用方法。然后循环等待用户输入,用户输入完成后,程序根据用户输入的选择不同的分支执行程序。若输入的内容为“quit”,则执行退出程序分支;若输入的内容为“help”,则执行显示帮助程序分支;若不是前两项内容,则执行算式计程序分支。分支执行完毕,继续等待用户输入。程序控制流程如下图所示:

图5 程序控制流程图

算式计算功能

计算算式并返回计算结果,计算前先对算式做语法判断,若算式语法错误,返回错误信息,终止计算功能。若算式语法正确,计算算式并返回计算结果。算式计算流程如下图所示:

图6 算式计算流程图

5、根据设计编写代码

程序流程控制

节程序流程控制功能一段给出了流程描述。按照流程描述,需要实现如下功能。

(1)建立run方法,在main方法中调用

在main方法中,声明类型为Arithmetic类成员变量tempArithmetic,并调用new方法初始化,然后调用Arithmetic类的run方法。

(2)显示帮助内容

需求部分要求帮助内容及显示格式如下:

***欢迎使用四则运算器***

算式计算:输入算式后,按下回车键,程序给出答案。算式仅限于算式仅支持包含单个运算符和两个运算数的算式。例如:15+20、8*9、20/5等。

退出程序:请输入“quit”命令,按下回车键。

查看帮助:请输入“help”命令,按下回车键。

Arithmetic类属性“help”存储帮助内容,showHelp()方法显示帮助内容。在Arithmetic类方法run中添加如下代码:

(3)循环等待用户输入

在程序顶部导入java.util包,在run方法中添加while循环代码,在循环体添加获取用户输入代码。

在run方法中,添加do-while循环语句,循环接收用户的输入,该循环为无限循环,后续代码需要添加退出循环语句。

(4)判断用户输入内容,选择不同程序分支

根据用户输入的内容,程序流程有三个分支。若输入的内容为“quit”,调用Arithmetic类的quit方法退出程序;若输入的内容为“help”,调用Arithmetic类的showHelp方法;若不是前两项内容,

调用Arithmetic类的calculateFormula方法。在run方法do-while循环语句中增加if-else语句。

 

算式计算

计算算式并返回计算结果,计算前先对算式做语法判断,若算式语法错误,返回错误信息,终止计算功能。若算式语法正确,计算算式并返回计算结果。

(1)语法扫描

扫描用户输入的算式,检查算式语法是否符合程序要求。语法正确与否判断规则如下:

● 算式的开始和结束字符必须是数字;

● 算式只能包含数字和‘+’、‘-’、‘*’、‘/’运算符;

● 运算符不能连续;

● 运算符有且只能包含一个;

在Arithmetic类的scanFormula方法添加如下代码:

/**

* Function scanFormula
* Description: 扫描formula算式,返回扫描结果
* input: 无输入参数
* return: formula算式无语法错误,返回sucess,否则返回语法错误
*/
public String scanFormula()
{
String result = "sucess";
String strFormula = getFormula();
char ch;
//声明count变量,存储运算符的出现的次数
int count=0;
//遍历strFormula
for( int i = 0; i < strFormula.length(); i++ )
{
//获取strFormula的第i个字符
ch = strFormula.charAt(i);
/**
* 判断ch是否是合法字符
* 合法字符为数字和‘+’、‘-’、‘*’、‘/’运算符
*/
if(ch >='0' && ch <='9')
{
continue;
}
elseif( ch=='+' || ch=='-' || ch=='*' || ch=='/' )
{
count++;
//算式的第一个字符和最后一个字符不能是运算符
if( i == 0 || i == strFormula.length()-1 )
{
result = "算式的第一个字符和最后一个字符不能是运算符";
break;
}
//算式只能包含一个运算符
if( count >= 2 )
{
result = "输入的算式只能包含一个运算符";
break;
}
}
else
{
result = "输入的算式包含非法字符,算式的第(" + i + ")个字符为非法字符";
break;
}
}
return result;
}

语法扫描采用遍历算式所有字符的算法,对算式的每个字符进行判断。for循环遍历算式的所有字符,for循环体的if-else语句判断算式的单个字符是否符合语法要求,如果不符合要求,设置语法错误信息并跳出循环。

(2)计算算式

具体算法为:遍历并解析算式,得到运算数和运算符,然后利用switch语句控制不同的计算分支,得到计算结果。

在Arithmetic类的calculateFormula方法添加如下代码:

/**

* Function calculateFormula
* Description: 计算formula存储的算式,返回计算后的结果
* input: 无输入参数
* return: 返回计算后的结果
*/
public String calculateFormula()
{
String result = "";
//声明num1和num2变量,用于存储运算数
String num1 = "";
String num2 = "";
//声明op,用于存储运算符
String op = "";
char ch;
//判断
boolean bFirst = true;
String strFormula = getFormula();
//遍历strFormula
for( int i = 0; i < strFormula.length(); i++ )
{
//获取strFormula的第i个字符
ch = strFormula.charAt(i);
if(ch >='0' && ch <='9')
{
if( bFirst )
num1 += ch;
else
num2 += ch;
}
elseif( ch=='+' || ch=='-' || ch=='*' || ch=='/' )
{
bFirst = false;
op += ch;
}
}
//计算算式
//获取运算符
ch = op.charAt(0);
//将字符串强制转换为double类型
double dNum1 = Double.parseDouble(num1);
double dNum2 = Double.parseDouble(num2);
double dResult = 0.0;
switch(ch)
{
case'+':
dResult = dNum1 + dNum2;
break;
case'-':
dResult = dNum1 - dNum2;
break;
case'*':
dResult = dNum1 * dNum2;
break;
case'/':
{
if( (int)dNum2 == 0 )
{
dResult = 0.0;
break;
}
dResult = dNum1 / dNum2;
}
break;
}
returnString.valueOf(dResult);
}

完善Arithmetic类的run方法

在Arithmetic类run方法循环体中增加算式语法扫描、计算算式、输出计算结果的代码。

publicvoidrun()

{
/**
* 初始化help,并显示help
*/
String strHelp = "***欢迎使用四则运算器***\n"
+ "算式计算:输入算式后,按下回车键,程序给出答案。算式仅限于算式仅支持包含单个运算符和两个整数运算数的算式。例如:15+20、8*9、20/5等。\n"
+ "退出程序:请输入“quit”命令,按下回车键。"
+ "查看帮助:请输入“help”命令,按下回车键。";
setHelp(strHelp);
showHelp();
/**
* 循环等待用户输入
*/
//声明Scanner变量,并用new运算符实例化Scanner
Scanner sc = new Scanner(System.in);
do {
String strInput = sc.next();
//判断用户输入内容,执行不同分支程序
if( strInput.equals("quit") )
quit();
elseif( strInput.equals("help") )
showHelp();
else
{
setFormula(strInput);
//语法扫描
String ret = scanFormula();
//语法正确
if( ret.equals("sucess") )
{
ret = calculateFormula();
printResult(ret);
}
else
{
//输出语法错误信息
printResult(ret);
}
}
}while(true);
}

至此,程序编写完成。

发布了118 篇原创文章 · 获赞 157 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/smilejiasmile/article/details/104618195