面向对象程序设计第三周期作业总结
0. 前言
本周期是面向对象程序设计这门课程的最后一个周期,作业难度较大,得分情况为100,90,84。后两次作业的丢分原因类似,都是没有正确地找到测试点,导致存在一到两个测试点无法通过。总体来说本次作业完成情况良好,对代码的重构,代码的设计,代码的复用性都得到了更好的理解和掌握,作为面向对象程序设计这门课程的结尾,本次作业总结整合了前面的知识和内容,也为之后有关java的学习打开了新大门。
1. 作业过程总结
a) 第一次作业要求对程序进行重构(Refactoring),在题目中所给的雨刷器代码的基础上,对代码功能进行拓展升级。
第二次作业是统计Java程序中关键词出现的次数,检测一段代码中,53个java程序出现的次数。
第三次作业是表达式求值,要求使用数据结构的栈,从键盘输入一个合法的表达式,对该表达式进行求值并输出。
b) 面向对象编程的三大技术特性在每一次的编程中都能加深理解,第一次的代码重构中,要添加新的雨刷系统类,要在新的类基础上添加功能,但是两种类又有很多相似之处,这时就体现了继承的必要性和实用性,新的雨刷类继承旧的雨刷类,然后再在主函数中选择不同的雨刷系统,从而选择不同的雨刷类别。多态体现在方法的重载和重写中,在第三次作业中,我写了一个判断是否为数字的方法,参数类型是char,但是在代码中参数类型不一定是char,有可能是String,所以我用到了重载,写了两种不同参数的方法,解决了这个问题。
public static boolean isOperator(char chr) { if (chr == '+' || chr == '-' || chr == '*' || chr == '/') return true; else return false; }
public static boolean isOperator(String str) { if (str == "+" || str == "-" || str == "*" || str == "/") return true; else return false; }
c) 本周期遇到的最大的问题是第三次作业中的数据结构有关栈的使用。第三次作业表达式求值需要用到暂时没有学过的数据结构和算法的内容,为了解决该问题,自行查阅了中缀式,逆波兰式,操作符栈,数值栈等在本题中的应用。理解了如何利用栈先进后出的原则对表达式进行求值。但是我在写代码的过程中,所有数字都定义为double类型,double类型在进行大数的运算时,会出现精度导致的误差,所以在发现问题后,将double类型的数据改为BigDecimal,如下:
/* * 计算后缀式的结果; 方法名:solve 返回值类型:double 参数类型:ArrayList<String> */ public static double solve(ArrayList<String> list) { double res = 0; Stack<String> stack = new Stack<String>(); for (int n = 0; n < list.size(); n++) { if (isnum(list.get(n))) {// 如果是数字则入栈 stack.push(list.get(n)); } else {// 如果是运算符则进行计算 switch (list.get(n)) { case "+": BigDecimal a = new BigDecimal(stack.pop()); BigDecimal b = new BigDecimal(stack.pop()); stack.push(a.add(b) + ""); break; case "-": BigDecimal one = new BigDecimal(stack.pop()); BigDecimal two = new BigDecimal(stack.pop()); stack.push(two.subtract(one) + ""); break; case "*": BigDecimal a1 = new BigDecimal(stack.pop()); BigDecimal b1 = new BigDecimal(stack.pop()); stack.push(a1.multiply(b1) + ""); break; case "/": BigDecimal mum = new BigDecimal(stack.pop()); BigDecimal sun = new BigDecimal(stack.pop()); if (mum.compareTo(BigDecimal.ZERO) == 0) { res = Double.NaN; return res; } stack.push(sun.divide(mum, 10, BigDecimal.ROUND_HALF_DOWN) + ""); break; }// switch } // if-else } // for res = Double.valueOf(stack.pop()); // System.out.println(res); return res; }
d) 因为本次周期的作业需要自行设计程序,所以花费的时间较以往来说更多一些,设计代码思路花费一到两天时间,实现代码需要一天时间,随后便是日常的debug阶段。
e) 编程的严谨性依旧是不容忽视的一个问题,在第二次作业中,Java的53个关键字由于不够严谨,导致传入HashMap时多加了几个空白符,导致出现bug,多次测试才找到最终问题所在。
2. OO设计心得
a) 开-闭原则在第一次的作业中感悟较深。开-闭原则要求软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的,在第一次作业中,拓展原程序,无需对原来的代码进行修改,而是在基础上拓展以达到修改代码的目的。
b) 在多次的练习中,对oo的设计有了一定的理解,也明白了static关键字的用法,如在第三次作业中,处理表达式的类是一个工具类,完全可以把方法定义为static,在调用方法的时候使用“类名.方法名”的方式来调用,减少了不必要的创建对象。
c) 关于类的设计我有一下几点感悟:
i. 类的起名。我认为类名的选择在编程的过程中极为重要,要尽可能地做到词达其意,看到类名就能明白类的作用,而不规范的类的命名在后续编程中会让代码的可读性急剧下降,在作者的编程中也会感觉吃力;
ii. 类的功能。类务必要做到单一职责,一个类执行一项职责,条例清晰。如果把多项职责都写在一个类中,会导致类变得冗杂,有悖于写类的目的。单一职责的每一个程序员都要掌握的。
iii. UML类图的使用。在自己编程中能够清晰地画出UML类图对编程的帮助是极大的,UML类图可以清晰地表示出类与类之间的关系和作用方式,先设计类图,再实现类图,这样的设计思路值得学习。
3. 测试的理解与实践
a) 测试是每次总结都要强调的一个问题,只有在测试的过程中才能发现代码的问题所在。作为一个IT小白,在编程的过程中往往会为了实现某个步骤而去写某段代码,殊不知这样的思维模式下,往往会忽略很多特殊情况,导致程序的运行中出现错误甚至崩溃。
b) Debug也是必备的一个技能,考自己的眼睛去找出程序的错误难上加难,需要通过debug一步一步检查每一个值,表达式的变化,找到异常的数值,进行修改,debug是编程中的一大利器,利用debug解决了大量复杂问题。
4. 课程收获
面向对象程序设计这门课程结束了,但是对于java的学习可以说刚刚开始,这门课程是面向对象程序设计的基础,培养了面向对象的编程思维,学习了java语言的精妙之处,掌握了Java的语法。
最重要的是通过这门课程提起了对java的浓厚兴趣,java语言是伟大的语言,也是程序员必须掌握的语言,能够通过一门课程引起对一个行业的热爱,这是我学习中最大的收获了。
5. 对课程的建议
在日后的课程中,可以适当地加入一些底层原理的知识,以及多一些实践,加大代码量才能有效提高学习的效率和知识掌握的速度。
在上课的过程中可以多利用实列来讲解某一功能,图文并茂。
6. 下一个阶段的学习计划和打算
a) 继续研究java中的集合如List,Map;
b) 学习Javafx的相关知识,设计GUI程序;
c) 对尚未完全掌握的java内容进行继续的学习,如拉姆达表达式;
d) 学习java的流式操作;
e) 自己设计实践,完成一个小型项目,并总结经验。