Java大作业5-6次总结

第一次迭代总体来说不难分析。它每个控制器和受控制器都是独立的,设计完之后就可以像拼积木那样来完成项目。感觉是封装思想的经典例题。
在进行类的设计时,由于题目中描述的类的实现采用的是元器件拼音首字母,因此为了方便记忆,我也使用了对应的拼音来定义类。这在实际使用时是不合适的。拼音并不是作为官方语言来使用的,容易对阅读性和代码习惯造成一些麻烦。
在设计受控设备类时,继承的setPower方法会根据输入电压分情况来输出。题目中虽然没有给出实际的表达式,但是可以用两点算出直线的算式。不过要注意的是,算式中的数值应当尽量准确,比如说300/7可以直接写成42.85714285171,否则由于浮点数运算精度的问题,得出的值将小于预期。例如下图。
image
同时边界值要直接使用题目中给出的值,不然去尾输出为int值后会导致误差而无法通过测试点。(过程值都是double类型,只有最后输出时才强制转换为int类型)
在设计控制设备类时,所有的档位默认为0,开关默认为关(false)。原本打算开关也用档位属性,但当时觉得这不符合常识,觉得开关就应该用Boolean类型,所以用了Boolean类型的OnOrOff。但实际上也是可以做到的——(默认档位为0)调用档位设置方法档位--就可以了;相反的情况,档位为1时档位++就可以了。
这里或许可以将“OnOrOff”改成“isOn”,这样意思没有改变,也更容易阅读。
在上述两种设计类时,虽然说有使用继承,但是也只是用了,基本都是重写而不是super,结构上看起来好一点而已。不过总比没有考虑好得多。只能说实际操作是一方面,思想又是一方面。总类图如下。
image
在设计主类时,由于只有一条电路,因此除输入电压VCC和接地GND外,所有地方的电压都是相同的。因而我在主类定义了一个静态变量VCC,至于为什么不是final而是变量,是为了让它被调节器作用后可以直接使用。这样在用电器设置输出情况(亮度、转速)时可以将VCC直接传入,列如上图中白炽灯类的setPower方法。
对于元器件,每个都逐一进行了初始化,这样后面就可以根据contains等方法读取到的字符串直接进行类的实现。但是这里没有考虑电路存在多个相同元器件的情况。
在读取输入时,我没有按回车而是按空格读取字符串,然后取巧地每隔一个读取一次(当然这也只适用于电路连接正常的情况)。使用了String类的substring方法与正则表达式截取前两个字符(如F1)来进行名字的设置,同时将该名字存入String链表以便后期遍历。
通过遍历链表获取的字符串来判断已有的元器件种类,据此来输出元器件的编号和工作情况(档位、亮度、转速等)。
这里有一段有趣且实用的代码。在设置调节器时,通过调用方法,用正则表达式来得到double类型的数来设置档位,如果没有匹配到,将抛出异常(本次迭代不会遇到),这种考虑符合健壮性的思想。具体方法如下。
image
在最开始,我新建了中间量doubleValue来存储并返回,但idea警告说该变量是冗余的,修改后如图。
image
从中可以得到这样一点信条:如果可以直接返回的话,不需要新建一个过程量。
在优化方面,或许可以采用类的链表来存储元器件,这样就省去了根据名字匹配元器件的过程。
圈复杂度方面,这里使用了idea的MetricsReloaded插件进行分析,如图。
image
image
image
从上图中可以不难分析,代码、主要是main方法的圈复杂度较高——具体来说,使用了大量的if-else嵌套来匹配不同的设备,从而导致了整个程序圈复杂度综合较高。其他方法的圈复杂度均不大于3。就这点来说,main方法有面向过程之嫌。
优化方面,或许可以将if - else if结构、do while循环提取成一个单独的方法,从而减少内部的分支结构,降低main方法的圈复杂度。

第二次迭代的代码与第一次相比,圈复杂度更是爆炸性的,main方法的平均复杂度来到了惊人的118.5,如图。image
image
image
image
原因也显而易见——大量的if-else嵌套,for循环嵌套,甚至在switch里嵌套if-else,这里举一段代码给大家看一下,尽是这样的代码,非常可怕。
image
使用穷举法来达成的算法就和冒泡排序一样,做了很多不需要的事情。虽然可能是我没有设计图中所画类图里的电路类造成的,但是我还是没办法想象,如何设计一个电路类使得它运行良好。这也是书到用时方恨少的一个体现,要不以后就叫这个名字吧(笑)。总之,阅历是需要积累的东西。
穷举法带来的另一个缺点则是,你没法确认你是否真的穷举了。你举的例子也只是你能想到的例子而已,可能最后也只是冰山一角。我也只是考虑了题设中给出的测试点,即每个元件最多有三个——电路1和电路2并联后与电路3串联,然而并联方式是否有其他情况,每条电路存不存在2个电路设备以外的情况——我没有考虑,也没有时间考虑了。
光是写完那些超长的if-else嵌套、for循环嵌套、switch嵌套if-else,就花了大量的时间。保证不看花眼就已经很累人了。这也是穷举法的一个缺点。
一复杂就没办法思考,这个坏习惯还是没法轻易改掉。要是突破了这个桎梏,说不准就能摸到更高的门槛。
说完缺点后来谈谈第二次迭代的新增注意点。
输入电压VCC设定为final类型,这样符合实际使用情况。在电路中,虽然可能会因为调节器导致实际电压改变,因为多个用电器导致分得的电压不同,但是VCC到底还是VCC,并没有因此而改变数值。档位调节、分配电压时再进行运算即可。这种考虑符合安全性的思想。
由于题中未给出元器件的电阻,因此这里只能假设控制设备不分压,而受控设备在电路中只有一种(防止其他受控设备电阻不同),这样电压的分配就明确了,然后用物理知识算出即可。
而对于类,本次采用了数组来存储,每一个数组也都建立了对应的变量count来记录使用的次数,这样最后for循环输出时就不会发生越界问题。另外,由于录入过程中setName时会发生name未定义的报错,因此在初始化时就将所有元器件命名为“NULL”。
在遍历数组输出元器件的编号和工作情况时,由于录入电路设备时顺序可能是乱的,需要根据名字来排序并输出。由于时间很紧,这里采用了直接的冒泡排序(毕竟每个元器件不超过3个,算法的优劣性不明显)排序后输出。本来有打算使用接口来获取名字,然后用该接口的方法来解决排序问题,但由于不熟练因此一直报错,最后不得不放弃。代码如下,也只是给出一种未实现的解决方案。
image
image
这两次迭代可以得出的结论是,如果发现有大段功能结构相似的代码,最好是提取成一个方法;如果有简单的方法,最好就采取更简单的方法。

posted @ 2024-11-23 00:09  如何去爱自己和他人  阅读(28)  评论(0)    收藏  举报