一、前言
——总结三次题目集的知识点、题量、难度等情况
- 关于知识点
这次的三次题目集更加进一步体现了面向对象程序设计的思想方法。主要是之前的三次题目集就只是利用了面向对象三大基础特性中的封装特性,而这三次的题目集增加了继承与多态,这正是面向对象设计的精髓所在,这三次的题目集大大增加了我对继承与多态这两个特性的理解与运用。除此之外,对于题目集四多种输入方法的正则表达式的匹配与分割的运用,以及Comparable接口的运用。题目集五六更加熟悉了抽象类的使用,以及容器类的使用。
- 关于题量
这三次编程练习中,第一次是对前三次答题判断程序编程作业的最终的迭代版本,需要考虑多种输入的题目类型以及答案类型,以及对他们的分割处理得到有效信息与各自的判断方法。后面两次是对家居电路的模拟。题量适中,同时题目的背景也贴合生活实际,便于理解。
- 关于难度
这三次的第一次作业练习,是在前三次的基础上迭代完成,只要深入理解题目,增加继承与多态,就可以完成题目。而后面两次,是关于对电路的简单模拟,只有串联主线路,或者在其基础上加上一个并联电路,主要是对代码中继承的设置,题目难度适中。
二、设计与分析
——主要是对题目以及自己提交的源码进行分析,加上自己浅浅的解释和心得
(一)题目集一
“答题判断程序四”
1.类图设计
2.源码分析
1.根据数据与雷达图分析:
- 分支语句占比总语句数的百分比为18.5%,此比例较低,说明此代码中分支逻辑较少,更易于理解与维护
- 在雷达图中注释语句占总语句数的百分比占比不高,说明我的代码可读性较差,可能也难以理解和维护,因此要增加代码的注释比例
- 最大复杂度这太高了主要原因是在controller中judgeAnswer()这个判断答卷对错的函数太复杂了,高达183行数,
而且里面还有二重嵌套循环,时间复杂度和空间复杂度较高。老师曾经说,一个函数的方法最多不超过50行为宜,因此这段代码质量不高,
后续自己写类似的代码的时候,需要对其进行适量的拆分,减小复杂度,增强可读性和维护性。
2.源码思路以及问题
(1)思路:
1)首先是读取信息,通过controller里面的input函数对读取的信息进行分流,对应到不同的函数进行信息处理工作,然后再组装试卷,组装试卷钱需要先遍历题库,将删除的题目设为删除,为后续做准备。组装试卷就是遍历题库与试卷,将其组装,输出试卷不足100分警示信息。考虑到题目对输出信息的顺序也有要求因此在判断答卷钱前,将答卷重新排序,为后续输出做准备。在这里排序有两种方式,一种是直接比较排序,另一种是写cmparable接口,我觉得后者构思更加巧妙,因此源码在此奉上:
@Override
public int compareTo(Answer t) {
if (this.getId().compareTo(t.getId()) > 0) {
return 1;
} else if (this.getId().compareTo(t.getId()) < 0) {
return -1;
} else {
if (this.getNumber() > t.getNumber()) {
return 1;
} else if (this.getNumber() < t.getNumber()) {
return -1;
} else {
return 0;
}
}
}
2)对于继承与多态在本题的体现,主要是创建的question问题父类,多选题目,填空题目等均继承于它,后续有其他种类的题目也可进行扩展。
(2)问题
这段代码的最大的问题就是在judgeAnswer函数里面,函数过于长,十分冗余,里面实现了找到答卷对应的试卷,判断题目对错(所有类型的题目判断对错都在里面了,明显可以出拆分成多个函数),以及构建分数,输出分数都在里面了。明显可以拆分成多个函数,降低函数复杂度与提高代码可读性以及可维护性。
(二)题目集二
“家居强电电路模拟程序一”
1.类图设计:
2.源码分析:
1.根据数据与雷达图分析:
- 这一段代码注释语句偏少,平均复杂度偏低,平均方法数偏低。
- 方法调用语句数为222,这次和上次都比第一到三次题目集增加颇多,说明自己的代码模块化程度进一步变高,的代码的复用性变得更高。
2.源码思路以及问题:
1)源码思路:
这次的是新的程序设计,具体思路和之前的答题顺序模拟思路不太一样。接下来说明。总体的思路是信息读入与信息处理—>信息读入的同时创建电路(这次模拟就只是模拟一个主线路,里面没有串并联具体电路的实现,较为简单)—>接着对组装好的电路进行电压赋值—>建立输出顺序按照特定格式输出。
所有的用电器与控制开关均继承自Device类,在Controller中创建Device类的Arraylist数组,用于模拟这条主线路。其中Device设为抽象类,内部包含getU得到电压的方法与view输出的方法这两个不能具体实现的方法。因为不同的用电器需要的电压不一样,输出形式也不一样。其实这样的只构建一个Device类并不好,因为完全没有考虑到后续迭代的增加的电路问题,这一点我会在下一题的分析中指出。
2)相关问题:
首先是对于引脚的处理问题,因为很明显根据实际,你一个用电器前面是输入引脚,后面是输出引脚,中间只有用电器这一个东西,是不会再夹层其他东西的,但是我在读取的时候考虑到了这个,不仅麻烦,在读取的时候要一遍遍遍历,大大增加了复杂度,占用空间资源。更关键的是,读取它之后并没有一点用处,这就是效益十分不高。
同时在做这一题时,最后有两个测试点一直过不了,直到我把电路里面的开关设置为断开时,发现用电器依然显示是有电状态,这就是问题所在,根据实际电路情况,当电路断开的时候,电路是不可能有电的,所以我在构建用电器电压时应当先对电路判断他是不是有电状态。
(三)题目集三
“家居强电电路模拟程序一”
1.类图设计:
2.源码分析1.根据数据与雷达图分析:
- 这一段代码注释语句偏少,平均复杂度偏低。
- 方法调用语句数为388,为历史新高说明自己的代码模块化程度进一步变高
- 行数达到了1117行,这是我第一次java编程破千行的代码
2.源码思路以及问题:
(1)源码分析
这一次的迭代主要是增加了不同的电路,包括串联电路以及并联电路。但是大体的思路和上面一题是一样的,这一点从我这未改动的main代码就可以看出来。但是最大的不同的是我这一次增加了abstaractCharge类,他是所有用电设备Device以及所有电路abstractCircuit的父类,因为考虑到一个主电路有串联电路,有并联电路,还有用电器。同时这一个并联电路也有串联电路,等等。因此在controller类里面可以定义一个abstaractCharge类型的Arraylist来当做电路存储信息,并通过instaneof判断类的类型,向下转型进行数据处理。
在最后的信息输出的时候,我定义了多个ArrayList存储开关,用电器等,遍历所有的电路,存储其对应的信息,再在最后依次输出。
(2)相关问题
这一题最大的坑在于当主电路只包含一个并联电路时的情况。按照物理知识我们知道,这时由于开关等控制电器没有电阻,因此并联电路两段的电压就是220。但是,凡事就在于这个但是,假如我们并联电路里面有两个串联电路,这两个串联电路的电阻是10欧姆和20欧姆,根据并联电路计算公式1/R = 1/R1+1/R2,因此我们的并联电路的电阻就为6.6666666666666667欧姆,没错就是这么精确,即便这么精确,也还是会出问题。我计算用电器两端的电压方式是:先算出一个电路两段的总电压和总电阻,再拿总电压除以总电阻,可以得到单位电阻对应的电压,然后用电器两端的电压就是单位电阻对应的电压乘以这个用电器对应的电阻。那么我们依据这个计算220/6.6666667,然后乘以6.66666667得到的并不是准确的220电压,就在于这个不能整除,最终在计算白炽灯的电灯亮度的时候: if (Math.abs(this.outputU - this.inputU) <= 9) { lamplight = 0; } if (Math.abs(this.outputU - this.inputU) == 10) { lamplight = 50; } if (Math.abs(this.outputU - this.inputU) > 10 && Math.abs(this.outputU - this.inputU) < 220) { lamplight = (Math.abs(this.outputU - this.inputU) - 10) * 1.0 / 210 * 150 + 50; } else if (Math.abs(this.outputU - this.inputU) >= 220) { lamplight = 200; } 他不会进入到>=220的分支语句中去,而是进入到<220的分支语句中去,因此计算的lamplight是199.9999999998可能,再根据截尾规则,直接舍去小数部分,这样算的lamplight就是199,而不是200,导致出错。因此我们在计算的时候要类似于比较大小的样子,<0.00001就认为二者相等,然后赋值成整数,这样就可以消除这方面的差错了。三、踩坑心得
1.遵循单一职责做的还不够好主要体现在第四次题目集也就是答题判断程序的最后一次迭代的题目里。某个函数长度很长,函数实现的功能也很复杂,包括了判断不同题目的对错,分数的计算等等。哪怕是自己看,也一时半会不能很好理解自己的思路,更不要说别人看自己的代码,则就更加难懂。 而且单一职责不仅体现在代码的可读性方面,还有代码的覆用性上。老师曾经在上课上的时候说过,一段代码的实现的功能越强,那么它被覆用的可能性就越低。 2.理论联系实际很重要 在软件这一领域,我们编写代码总是要立足于某些东西,实现某些功能,并不是说是空穴来风,没有立足点。因此我们编写代码的时候,要明白给谁编写,编写什么,这个编写的是什么,他这一个领域有哪些知识需要你学习,因为你编写代码可能会用到那些领域的知识。例如在家庭电路简单模拟中,我因为忽略了电路断电就用用电器不能工作这一事实,导致没有实现这一功能。当然,我考虑欠缺也是一部分原因,自己也是要更加考虑周全。
3.时刻明白编程和实际计算中的不同之处
例如我在第三次题集的问题分析中指出的,因为计算的精度的问题,计算的电压不是完整的220V,导致的错误,这完全是自己在写代码的时候自己想当然的结果导致的错误。
四、改进建议
代码优化:
1.对于部分函数进行精简,使其结构单一,提高覆用性,与可读性
2.代码中变量的命名,函数名字的命名不太规范,也需要之后改进
3.降低嵌套循环层数,减少空间与时间复杂度
结构优化:
1.对于串联中有串联电路,并联中有并联电路,等复杂电路的情况自己没有考虑,需要在日后的迭代中加入这些功能
2.减少if-else等的情况判断
五、总结
这三次题目集大大增强了我对继承与多态这两大特性,抽象类,向下转型,泛型,常用接口等基础知识的理解与运用。尤其是最后一题,大大增加了我对继承的理解,如果不是让让电路和用电器都继承自同一个类,那么我在构建电路的时候就会要麻烦很多。充分体现了面向对象语言的方便性。
然后在开闭原则上我也有了更加深刻的领悟。在上一部分的pta中,我很清楚地记得每一次的代码我都是新建一个项目工程,从主函数一个一个开始敲,自己完全没有是在之前代码的基础上进行修改,而是不断重构。不仅费时费力,也完全没有深刻理解面向分对象语言的方便性。但是在最近两次的pta练习,引入了继承之后,自己的每次代码则是从上一次的代码的基础上进项修改,扩展。当然这个进步离不开老师的辛勤教导与线上课,线下课,实验,pta多个合一的结果,感谢老师的教导!!
最后希望下一阶段给自己的目标是一是可以预测之后Pta会向哪方面的迭代,提高自己代码的质量,争取一次比一次代码改动的方面更少。二是将老师上课讲到的设计模式用到一二,学以致用,提高自己代码编写水平。
谢谢!!
标签:题目,苏礼顺,用电器,Blog,电路,源码,并联,java,代码 From: https://www.cnblogs.com/Zurichsls/p/18227190