文章目录
软件工程实践 | 2301-计算机学院-软件工程社区-CSDN社区云 |
---|---|
作业要求 | 软件工程实践第一次作业-CSDN社区 |
作业目标 | 完成一个具有可视化界面的计算器。 |
其他参考文献 | … |
成品展示
Gitcode项目地址
亦瑾z / SE_ex1_calculator · GitCode
PSP表格
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | ||
• Estimate | • 估计这个任务需要多少时间 | 5 | 3 |
Development | 开发 | ||
• Analysis | • 需求分析 (包括学习新技术) | 20 | 30 |
• Design Spec | • 生成设计文档 | 10 | 15 |
• Design Review | • 设计复审 | 5 | 5 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 0 | 0 |
• Design | • 具体设计 | 30 | 40 |
• Coding | • 具体编码 | 250 | 300 |
• Code Review | • 代码复审 | 10 | 20 |
• Test | • 测试(自我测试,修改代码,提交修改) | 20 | 40 |
Reporting | 报告 | ||
• Test Repor | • 测试报告 | 20 | 30 |
• Size Measurement | • 计算工作量 | 3 | 5 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 10 | 30 |
合计 | 383 | 518 |
解题思路描述
问题1 图形化界面
Q: 如何使用Java实现图形化界面
- 使用Swing框架, 用
ActionListener
来获取用户按下的按键
问题2 计算
Q: 如何实现计算器的底层计算
- 使用中缀表达式转后缀表达式计算求解 ×
- 编码时间过长, 有可能出现来不及提交的问题
- 使用表达式计算库求解 ✓
接口设计和实现过程
计算器图形化框架搭建
Calculator
类中继承JFrame类, 使用两个JPanel(textPanel
, 和buttonPanel
)搭建出UI界面Calculator
类实现了ActionListener
接口- 为button添加了监视(
buttons[i].addActionListener(this);
) - 重写了
actionPerformed(ActionEvent e)
方法, 当按下button后, 会调用handleEvent(String command)
对事件进行处理
- 为button添加了监视(
- 定义了内部类
class MyKeyListener extends KeyAdapter
, 监听键盘, 实现计算器的键盘输入
表达式计算
主要在
private void handleEvent(String command)
方法中实现
表达式处理
主要思路为: 针对不同command, 对当前表达式进行修改, 当"=".equals(command)
时, 计算结果
- < =: 进行退格操作
- 为简化if else代码段, 将其具体实现定义到
CalculatorMethod.back()
中
- 为简化if else代码段, 将其具体实现定义到
- C: 清除表达式, 并且进行置零
- π: 转化为3.1415……
- 普通计算符:
{"^2", "^", "/", "*", "-", "+"}
保存中间表达式 - 复杂计算符:
{"sin", "cos", "tan", "√"}
对表达式进行一些额外操作(如添加括号) - 普通数字: 直接加在表达式后
表达式计算
主要在
CalculatorMethod类
中static void calculate(JTextField textField1, JTextField textField2)
方法实现
- 对两段表达式合并, 调用基于parsii库的
.evaluate()
方法, 对计算结果的显示效果进行处理 - 此外, 对异常进行了catch
关键代码展示
-
图形界面搭建
public Calculator() { setSize(new Dimension(panelWidth, panelHeight)); setTitle("Calculator by zjj"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // BorderLayout 是一种常用的布局管理器,将容器分为五个区域:北、南、东、西和中间。每个区域只能放置一个组件。 setLayout(new BorderLayout()); initFuncSet(); initTextPanel(); initButtonPanel(); // 相对屏幕居中显示 setLocationRelativeTo(null); setVisible(true); // 添加键盘监听 addKeyListener(new MyKeyListener()); // 获取焦点 addWindowListener(new WindowAdapter() { @Override public void windowActivated(WindowEvent e) { // 在窗口激活时重新请求焦点 requestFocusInWindow(); } }); }
-
对监听到的事件进行处理
private void handleEvent(String command) { if (cleanTextFlag) { JTextFieldUtil.cleanTexts(textField1, textField2); cleanTextFlag = false; } String text1 = textField1.getText(); String text2 = textField2.getText(); if ("=".equals(command)) { // 得出答案 / 异常, 下一次按键后需要清空值 cleanTextFlag = true; CalculatorMethod.calculate(textField1, textField2); } else if ("<=".equals(command)) { CalculatorMethod.back(textField2); } else if ("C".equals(command)) { if (text2.equals("0") || text2.isEmpty()) { JTextFieldUtil.cleanTexts(textField1, textField2); } else { CalculatorMethod.zeroing(textField2); } } else if ("π".equals(command)) { textField2.setText(String.valueOf(Math.PI)); } else if (simpleFuncSet.contains(command)) { // 输入了普通计算符, 暂存中间的表达式 textField1.setText(text1 + text2 + command); JTextFieldUtil.cleanText(textField2); } else if (complexFuncSet.contains(command)) { // 输入了复杂计算符, 暂存中间的表达式, 但需要补() if ("√".equals(command)) { command = "sqrt"; } textField1.setText(text1 + command + "(" + text2 + ")"); JTextFieldUtil.cleanText(textField2); } else { if ("0".equals(text2) && ! ".".equals(command)) { text2 = ""; } textField2.setText(text2 + command); } }
性能改进
在handleEvent
方法中使用HashSet对command进行分类判断, 将查询时间复杂度将至为O(1)
单元测试
使用parsii表达式计算库, 不需要对库本身做过多测试, 主要测试某些可能的command是否会出错
使用JUnit测试框架, 对计算机中的主要功能进行了测试
public class CalculatorMethodTest {
JTextField textField1 = new JTextField();
JTextField textField2 = new JTextField();
@Test
public void testSin() {
textField2.setText("sin(0.5*3.1415)");
CalculatorMethod.calculate(textField1, textField2);
System.out.println(textField2.getText());
}
@Test
public void testCos() {
textField2.setText("cos(0.5*3.1415)");
CalculatorMethod.calculate(textField1, textField2);
System.out.println(textField2.getText());
}
@Test
void testTan() {
textField2.setText("tan(0.5*3.1415)");
CalculatorMethod.calculate(textField1, textField2);
System.out.println(textField2.getText());
}
@Test
public void testSqrt() {
textField2.setText("sqrt(81)");
CalculatorMethod.calculate(textField1, textField2);
System.out.println(textField2.getText());
}
@Test
public void testDivZero() {
textField2.setText("9/0");
CalculatorMethod.calculate(textField1, textField2);
System.out.println(textField2.getText());
}
@Test
public void testIllegalExpression1() {
textField2.setText("9//");
CalculatorMethod.calculate(textField1, textField2);
System.out.println(textField2.getText());
}
@Test
public void testIllegalExpression2() {
textField2.setText("9+-*/");
CalculatorMethod.calculate(textField1, textField2);
System.out.println(textField2.getText());
}
}
- 关于覆盖率的优化: 针对边界值和极端情况进行测试,例如最大值、最小值、空值等。这有助于发现在边界条件下可能存在的错误和异常情况。并且针对无法计算的表达式进行异常的处理。
- 但是图形化界面的计算器并不能够直接进行单元测试,在计算器的输入模块中,有可能依然存在bug
异常处理
调用evaluateExpression
后, 对可能抛出的异常ParseException, EvaluationException
进行catch
try {
result = evaluateExpression(expression);
textField1.setText(expression + "=");
if (result.intValue() == result) {
// 结果为整数,去掉.0
textField2.setText(String.valueOf(result.intValue()));
} else {
textField2.setText(String.valueOf(result));
}
} catch (Exception ex) {
// 表达式错误, 将异常显示到屏幕
textField2.setText("表达式非法,请重新输入");
}
心得体会
完成一个具有可视化界面的计算器项目是一次很有收获的软件工程实践经历。
在开始编写代码之前,我对项目需求的分析不够完成全面。这导致我在动手编码时反复地修改计算器的计算逻辑和展示结果方式,造成了很大的时间浪费。
在图形界面搭建阶段,我快速地学习Swing并上手搭建了一个直观、易于使用和美观的用户界面。
在编码过程中,我将整个项目划分为多个模块(方法),每个模块负责不同的功能。这种模块化的设计使得代码更具可读性和可维护性。我编写了简洁、高内聚的方法,并尽量避免了代码的冗长和重复。
新输入");
}
## 心得体会
完成一个具有可视化界面的计算器项目是一次很有收获的软件工程实践经历。
在开始编写代码之前,我对项目需求的分析不够完成全面。这导致我在动手编码时反复地修改计算器的计算逻辑和展示结果方式,造成了很大的时间浪费。
在图形界面搭建阶段,我快速地学习Swing并上手搭建了一个直观、易于使用和美观的用户界面。
在编码过程中,我将整个项目划分为多个模块(方法),每个模块负责不同的功能。这种模块化的设计使得代码更具可读性和可维护性。我编写了简洁、高内聚的方法,并尽量避免了代码的冗长和重复。
这个项目是一个很好的学习机会,让我将课堂上学到的知识应用到实际项目中。我深入了解了Java编程语言、用户界面设计、软件开发流程等方面的知识。通过实践,我发现自己的编程能力和解决问题的能力有了明显的提高。