第二次博客作业
一、前言
??在上个阶段,我们学习了集合与集合框架、java8的新特性以及JavaFX的一些初步介绍。自上个阶段以来我们做了浙大PTA的三次题目集作业,两次链表课上作业,一次农夫过河实验作业,而本次博客将分析其中三道较有分析价值的题目。
二、代码质量检测术语
1. 方法复杂度分析中的术语(IDEA-Metrics):
??
CogC: Cognitive complexity,认知复杂度,用来衡量代码被阅读和理解时的复杂程度。每种控制结构的使用都会增加认知复杂性,而且嵌套的控制结构越多,认知复杂性就越高。
??ev(G): Essential complexity,基本复杂度,用来衡量程序非结构化程度,ev(G)高意味着非结构化程度高,难以模块化和维护。
??iv(G): Design complexity,设计复杂度,与方法控制流与对其他方法的调用之间的相互联系有关,也代表了将方法与其调用的方法进行集成所需的最少测试次数。
??v(G): Cyclomatic Complexity,圈复杂度,是通过每个方法的不同执行路径数量的度量,可以看作是完全执行方法控制流所需的最少测试次数。圈复杂度 = 1+ if、while、for、do、switch cases、catch、条件表达式、&&'和||的数目。
2. 类复杂度分析中的术语:
??
OCavg: Average operation complexity,计算每个类中所有非抽象方法的平均圈复杂度。继承的方法不计算在内。
??OCmax: Maximum operation Complexity,计算每个类中非抽象方法的最大圈复杂度。继承的方法不计算在内。
??WMC: Weighted method complexity,计算每个类中方法的圈复杂度总和。
三、设计与分析
1. ATM类设计(PTA212019班-题目集06)
TASK:编写一个银行 ATM 机的模拟程序,能够完成用户的存款、取款以及查询余额功能。
设计策略:
??此次作业的难点主要是用户相关数据的结构设计,一个人可以有多个账户,每个账户又有多张卡,笔者在这里涉及三个存储相关数据的类,分别为Name、Account、Card,Name类中定义了一个Account类型的集合,Account类中同样定义了一个Card类型的集合,由此嵌套存储数据,此次作业是笔者对于Array List集合框架的第一次尝试。
类图如下:
方法和类复杂度分析:
???
优点:
数据类层层嵌套构成了一个可读性非常高的数据结构,各个类之间分工明显,耦合性较低,整个结构的可读性还是非常高的。
缺点:
通过方法和类复杂度分析,可以看出Check类与GUI类复杂度高到了一个令人惊叹的程度,通过对两个类的检视以及在网上学习他人的代码,笔者认为在这两个类的设计思路上应该是没有问题的,最大的问题就是笔者在这两个类里面将所有的方法都放在一个函数里面,这明显违背了函数设计的单一职责原则。
另外,题目中给出了中国银联这一概念,而笔者却因为题目中未有相关操作而放弃设计这一概念,这会对后续代码的拓展与修改带来很大的困难。
两个类中一个函数里面都有三个for与三个if大大增加了代码的复杂度,致使代码可读性极低
设计原则检查:
Singe Responsibility Principle:GUI类与Check类严重不符合单一职责原则
Open Close Principle:数据库类将每一个用户视作一个类,后续的拓展与修改很方便,个人认为这一部分是符合开闭原则的
Liskov Substitution Principle:由于不存在子类,因此满足里氏替换原则
Interface Segregation Principle:由于不存在接口,因此满足接口分离原则。
Dependency Inversion Principle:由于不存在依赖关系,因此满足依赖倒置原则。
2. 点线形系列4-凸四边形的计算(PTA212019班-题目集07)
TASK:用户输入一组选项和数据,进行与四边形有关的计算。
设计策略:
??在上一阶段我们已做过与此题目极其类似的图形类设计题目,回顾上次的类设计可谓是惨不忍睹,除Main类之外再无其它类,敢问这还是面向对象语言吗?毫无疑问,上次的设计将犹如一把达摩克利斯之剑一样高高悬在我的头上,作为今后人生道路与编程设计的制约。因此本次作业笔者参考了上次作业的参考类图,设计点、线、三角形、四边形与斜距式方程这些类并把他们看作新的类型,并设计控制类,以及设计输入数据处理类、输入错误处理类与输出格式类。
类图如下:
方法和类复杂度分析:
优点:
不管实际如何,此次作业的类设计相比于上次实现了飞跃性的提升,不信的话我们看看上次的设计,真的是非常的恶心!相比于上次的悲惨设计,此次作业类与类之间能够各司其职,耦合性与复杂度大大降低,各个方法都已经尽我最大的努力实现单一职责原则,代码的拓展性也大大提高。
上次作业
缺点:
我们可以通过类复杂度分析看出,多边形类也就是四边形与三角形的父类复杂度很高,这是因为其中的分开面积方法复杂度惊人的达到了50,这是很没办法的事情,因为笔者数学能力的问题。
另外,关于Control类的复杂度偏高问题,笔者认为是其中的判断多边形类型方法并不是很符合单一职责原则,并且Control类中五个handle函数的复杂度应该是相同的,但却有较高的两个handle,其实这些问题都是一个问题,都是笔者因为题目长度限制而牺牲了某些部分的单一职责设计,导致这些方法变得比以往更加复杂。
因此,本次类设计的第二个缺点便是代码长度问题,笔者就目前知识储备而言,并没有能力严格的控制代码长度,这也是笔者要深切关注的问题。
设计原则检查:
Singe Responsibility Principle:诸如separateArea类、isTriOrQuad类,凡是这些涉及到数学计算的类,笔者没有保证单一职责的实现。
Open Close Principle:将每一种图形以新类型的形式进行类设计,个人认为符合开闭原则
Liskov Substitution Principle:本次类设计只是因为想让三角形类与四边形类有一个共有的方法而设计了一个父类,个人认为这样的设计并不能给人一种这是父类与子类的感觉,所以个人认为不符合里氏代换原则。
Interface Segregation Principle:由于不存在接口,因此满足接口分离原则。
Dependency Inversion Principle:三角形与四边形两个类只依赖于抽象类,因此满足依赖倒置原则。
3. 实验4-继承与多态
TASK:以如下类图为基础,重构实验二中农夫过河游戏的代码。
设计策略:
??非常诚实的说,此次类设计是我在看了班内某个同学的代码后做的,虽然说类设计已经给出,但是其中的抽象、依赖、接口部分需要我们自己去构思,得出一个耦合性与复杂度均比较低的设计结构,在看了那位同学的代码,我才明白什么是真正的继承与多态,以及里氏代换原则到底想表达什么,可悲的笔者在之前凡是有关继承与多态的结构设计,全部都是父类有的子类全部要有,父类全部都是抽象方法,子类也没有自己的方法,这一点在上次博客作业的某次雨刷作业中可以看出来。于是此次类设计笔者几乎是完全参考那位同学的设计以及做了一些微小的改良,使得规则类与数据类耦合性降低了一些,完全符合给出的类图。
类图如下:
方法与类复杂度分析:
优点:
此次类设计思路清晰,各个类分工明确,整体结构可读性强,耦合性与复杂度低,五个抽象父类使得代码结构的拓展性提高。
缺点:
第一,笔者首先想说的就是,在关于高兴与哭泣接口的题目要求中,题目的想法是每个生物都要尽可能的有自己独特的方法,然而在此次类设计中,我们如果想要区分狼和羊就很难区分,因为 他们只不过是名字不同的animal类。
第二,我们可以看见Boat类中的下船方法稍有复杂,这是因为笔者进行很多次没必要的异常判断,通常我们只判断其中的一种异常情况就行了,因为基本所有的异常情况都是同一判断机制,然而笔者或是因为丧心病狂的想要显示出代码是因为哪种异常情况而产生异常从而在判断上做了很多的嵌套,这种想法或许没问题,但做法有待商榷,如果因此大大增加了方法的复杂度,那我认为这种做法是没有必要的。另外,笔者做出这种举动的最大原因可能是思考不够,没有找到这些异常情况的共性。
第三,Game类中的play方法复杂度很高,这是因为没有实现单一职责原则。
设计原则检查:
Singe Responsibility Principle:Game类中的play方法笔者便没有实现单一职责原则,各种异常处理也是并未实现。
Open Close Principle:交通工具、生物、游戏模式与游戏数据均作了继承与多态设计,个人认为符合开闭原则。
Liskov Substitution Principle: 每个子类拓展了父类的功能且没有改变父类原有的功能,个人认为符合里氏代换原则。
Interface Segregation Principle:每个接口中只有一个方法,因此满足接口分离原则。
Dependency Inversion Principle:各子类只依赖于一个抽象类,因此满足依赖倒置原则。
四、这一阶段的总结
相比于上一阶段,笔者已能在写代码之前进行类设计,可以说是正式踏入了面向对象世界,回顾这一阶段的类设计,发现了一个共性问题,便是笔者在进行方法设计时很少注意单一职责原则的规范,这个问题需要注意。对于其他设计原则,笔者也有了更加深刻的认识。
既然继承与多态部分笔者已有很大提升,在下一阶段,笔者认为应熟悉接口并能熟练运用接口,另外,对于JavaFX也应迅速做到初步掌握。