基于度量的程序结构分析

由于平时使用了NetBrains出品的IDEA作为IDE,在分析程序的时候我使用了IDEA的插件Metrics Reloaded。然而在使用时发现不懂得很多分析项目的含义,因此花费了一些时间了解,并在这里总结。

Complexity Metrics(复杂度分析)

这部分我们需要使用的主要是方法和类的复杂度分析。

方法的复杂度分析主要基于循环复杂度的计算。循环复杂度是一种表示程序复杂度的软件度量,由程序流程图中的“基础路径”数量得来。

  1. ev(G):即Essentail Complexity,用来表示一个方法的结构化程度,范围在$[1,v(G)]$之间,值越大则程序的结构越“病态”,其计算过程和图的“缩点”有关。

  2. iv(G):即Design Complexity,用来表示一个方法和他所调用的其他方法的紧密程度,范围也在$[1,v(G)]$之间,值越大联系越紧密。

  3. v(G):即循环复杂度,可以理解为穷尽程序流程每一条路径所需要的试验次数。

    对于类,有OCavgWMC两个项目,分别代表类的方法的平均循环复杂度和总循环复杂度。

Dependency Metrics(依赖度分析)

依赖度分析度量了类之间的依赖程度。有如下几种项目:

  1. Cyclic:指和类直接或间接相互依赖的类的数量。这样的相互依赖可能导致代码难以理解和测试。
  2. Dcy和Dcy:计算了该类直接依赖的类的数量,带表示包括了间接依赖的类。
  3. Dpt和Dpt:计算了直接依赖该类的类的数量,带表示包括了间接依赖的类。

第一次作业

类图如下:

这次作业比较简单,当时也很很努力的用来OO思想。但从算法角度来说效率比较低。除了面向对象对象思想之外,还学习到了正则表达式和异常处理。

第二次作业

类图和度量分析图如下:

Method ev(G) iv(G) v(G)
"Building.Building(int,int)" 1 1 1
"Building.getMaxFloor()" 1 1 1
"Building.getMinFLoor()" 1 1 1
"ERequest.ERequest(int,double)" 1 1 1
"Elevator.Elevator(Building,double,double)" 1 1 1
"Elevator.getFinishTime(int,double)" 1 1 1
"Elevator.gotoFloor(int,double)" 1 3 3
"FRequest.FRequest(int,double,String)" 1 1 2
"FRequest.getDirection()" 1 1 1
"FRequest.isSame(Object)" 2 1 2
"Request.Request(int,double)" 1 1 1
"Request.getFloor()" 1 1 1
"Request.getTime()" 1 1 1
"Request.isIllegal(int,double,Building)" 1 3 3
"Request.isSame(Object)" 4 1 4
"Request.parse(String,Building)" 5 3 5
"RequestQueue.RequestQueue(Building)" 1 1 1
"RequestQueue.finishRequest()" 1 1 1
"RequestQueue.getRequest()" 1 1 1
"RequestQueue.inQueue(Request)" 3 2 3
"RequestQueue.isEmptyQueue()" 1 1 1
"RequestQueue.isIllegal(Request,double)" 4 7 7
"RequestQueue.readAll()" 12 8 12
"RequestQueue.updateNext()" 1 1 1
"RequestQueue.updateUntil(double)" 1 4 4
"Scheduler.Scheduler(Elevator,Building)" 1 1 1
"Scheduler.command()" 1 3 3
"Scheduler.main(String[])" 1 1 1

由于程序本身比较简短,度量工具看不出太多的问题。程序的耦合状况还可以。主要是用于输入的RequestQueue.readAll()的复杂度较高,可以通过将方法进行拆解,提高可读性。

我将两种请求继承自一个Request父类,而在最近阅读《Java核心技术》时,我发现可以在Request类中增加一个工厂方法来进行字符串的解析,而不是把字符串的解析放到请求类本身的构造函数中。

第三次作业

类图和度量分析图如下。

Class OCavg WMC Cyclic Dcy Dcy* Dpt Dpt*
ALS_Scheduler 3.5 21 0 10 10 0 0
Building 1 3 0 0 0 5 8
ERequest 1 2 2 1 5 2 7
Elevator 1.75 21 0 4 6 3 4
FRequest 1.5 6 2 3 5 3 7
HitchHikerQueue 2.22 20 0 5 9 1 1
Movable.Direction n/a 0 0 0 0 5 8
Request 1.88 15 2 3 5 7 7
RequestQueue 2.25 27 1 3 8 3 3
Scheduler 2.5 10 1 6 8 2 3

限于篇幅没有给出方法的度量,但是可以发现复杂度较高的方法有HitchHikerQueue.getNextFloor()RequestQueue.readAll()ALS_Scheduler.isHitchHikable()。这三个方法的作用分别是得到在考虑捎带请求的情况下的下一个停留楼层,读入所有请求,以及判断当前请求是否可以被捎带。其中读入请求的方法不可避免,而另外两个方法则由实现方法导致。不过仔细检查之后确实发现了getNextFloor()方法可以简化的地方。

这次作业的思路是由请求队列RequestQueue读入和保存当前正在等待的请求,增加一个HitchHikerQueue类保存正被捎带的类,电梯类Elevator则保存了当前运动信息,具有有输出功能,Scheduler负责调度。

这次作业的设计基本延续上次的思路,为了努力达到OO思想(实际上是偷懒符合符合直观),我设计了等待请求队列,捎带请求队列和带有所有运动信息和输出功能的电梯。但这样也给我带来了很多麻烦。原因如下:

  1. 将三个队列分开来使得时间信息被打乱,尤其是会有同时间但是先后顺序不同的请求。一开始我以为只要三个队列保持各自的顺序就行了,实际上后期对拍发现会有更加复杂的情况。因此我后来给每个请求都加上了时间戳,每次对队列进行修改都需要重新排序一次。现在回想,其实可以队列用两个优先队列实现,保存相同的元素,但是一个以时间戳作为key,另一个以楼层作为key(因为我的设计中需要不断找出下一个最近的楼层)。
  2. 因为指导书中提到用电梯的toString()输出,而且为了更好的OO,我把保存运动信息,输出状态,判断捎带的部分功能都移到了电梯中,又大大增加了复杂度。
  3. 出现了一些语法错误,例如在foreach语句中不能删除所迭代对象的元素。不过这些错误倒是帮助我学习到了一些关于迭代器,lambda的知识

互测部分

说实话,三次作业拿到的代码都不算太好,还是比较面向过程的。三位同学都采用了一个个扫字符串处理输入而不是正则表达式反向匹配,而且在之后电梯的代码量又较大,让我很难把代码读进去。

因此,在测试过程中,我主要是把自己的测试数据或者对拍来找出对方的错误,然后调试程序找到错误点,找到原因并进一步发掘更多的错误点。

第一次作业

对方:第一位同学主要出错在数据处理上,比较原始的字符串处理方式难免的弊端。

我方:这次作业是我唯一被测出问题的一次,问题在于对指导书的理解有问题。我将指导书所说的不输出零项理解为了不输出次数为0的项,从而造成错误。

第二次作业

对方:第二位同学则是由于INVALID格式的问题,错误树上几乎被挂满。但我还是找出了一些边界条件上处理的错误,这位同学把关门时刻的请求当做了非同质请求,十分可惜。另外,他的输入在某些情况下会导致指针越界,是使用原始数组的弊端了。

我方:这次没有被测出Bug

第三次作业

对方:第三位同学在我一系列时间的对拍后都未出现错误,倒是代码中通过以0.5s为粒度的模拟方式比较有意思。虽然比较低效,但是使得程序难以出错。

我方:这次没有被测出错误

总结

这三次作业中,我对第三次作业比较不满意。一是因为开始写代码之前没有想清楚,造成后来拆东墙补西墙。另外这次作业还是有一些算法的意思在里面,以我的实现方法,就需要一个高效的数据结构,然而当时只是为了让程序跑起来,并没有想太多。

2018-北航-面向对象-前三次OO作业分析与小结的更多相关文章

  1. 【作业】HansBug的前三次OO作业分析与小结

    OO课程目前已经进行了三次的作业,容我在本文中做一点微小的工作. 第一次作业 第一次作业由于难度不大,所以笔者程序实际上写的也比较随意一些.(点击就送指导书~) 类图 程序的大致结构如下: 代码分析 ...

  2. 2018-北航-面向对象第三次OO作业分析与小结

    1. 规格设计的发展历史 规格设计用于对程序设提供分解,抽象等的手段.在撰写代码规格的时候,需要对组成部件进行抽象. 在1960s,软件设计出现危机,例如Dijkstra提出了goto语句的种种危害, ...

  3. 前三次OO作业总结

    一.作业总结 前三次的任务都是表达式求导.这是我在高中就思考过的问题,但是很久都没有付诸实践,直到学习了"类"这个强大的工具.还有正则表达式,如果能适当使用,则不失为一个字符串格式 ...

  4. 前三次OO作业小结

    I used to be enamored of object-oriented programming. I'm now finding myself leaning toward believin ...

  5. 2018-北航-面向对象567次OO作业分析与小结

    设计策略及其变化 第五次作业-多线程电梯 在这次作业一开始的大部分时间,我一直想着怎样设计最为完美,完全使用BlockingQueue,导致交作业前发现设计并不能满足指导书的要求.最后仓皇之中加了一个 ...

  6. 【作业2.0】HansBug的5-7次OO作业分析与小结,以及一些个人体会

    不知不觉又做了三次作业,容我在本文胡言乱语几句2333. 第五次作业 第五次作业是前面的电梯作业的多线程版本,难度也有了一些提升.(点击就送指导书) 类图 程序的类图结构如下: UML时序图 程序的逻 ...

  7. 北航oo作业第一单元小结

    前言 在经过了三次艰辛的oo作业后,oo课程的第一单元告一段落,这一单元,我作为一个oo小白,开始了解oo的编程思想,也有了自己的一点心得体会.把笔粗成字,不当之处,还请各位大佬多多指教. 一.分析程 ...

  8. 北航oo作业第二单元小结

    类的设计: 首先,我对我的思路进行整体的说明,由于我的三次作业,思路是继承的,所以做总体的说明 第一,   Main类,Main类自身并没有功能,他的功能只是构造需要的电梯线程和输入线程. 其中,第三 ...

  9. CS231n 2016 通关 第三章-SVM 作业分析

    作业内容,完成作业便可熟悉如下内容: cell 1  设置绘图默认参数 # Run some setup code for this notebook. import random import nu ...

随机推荐

  1. keepalived weight正负值问题(实现主服务器nginx故障后迅速切换到备服务器)

    有两台负载均衡,lb01,lb02.  lb02, priority值为100 编辑keepalived配置文件   vim /etc/keepalived/keepalived.conf ! Con ...

  2. Java try和catch的使用介绍

    尽管由Java运行时系统提供的默认异常处理程序对于调试是很有用的,但通常你希望自己处理异常.这样做有两个好处.第一,它允许你修正错误.第二,它防止程序自动终止.大多数用户对于在程序终止运行和在无论何时 ...

  3. P3371 【模板】单源最短路径(弱化版)(Dijkstra算法)

    题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三 ...

  4. Jmeter接口测试+压力测试+环境配置+证书导出

    jmeter是apache公司基于java开发的一款开源压力测试工具,体积小,功能全,使用方便,是一个比较轻量级的测试工具,使用起来非常简单.因为jmeter是java开发的,所以运行的时候必须先要安 ...

  5. Java连接数据库 #05# SQL与代码分离

    索引 读取html中的SQL语句 缺陷总结 在Java连接数据库 #04#里大概是这样放sql语句的: package org.sample.shop.db.queryrunner; import o ...

  6. Flutter从零到∞学习笔记

    有状态widget:StatefulWidget和无状态widget:StatelessWidget 前者不需要实现Widget build(BuildContext context). 具体的选择取 ...

  7. Linux 系统级开启文件句柄 调优

    系统级开启文件句柄  max-file系统级别的能够打开的文件句柄的数量,Centos7默认是794168. Max-file 与 ulimit -n 的区别 max-file 表示系统级别的能够打开 ...

  8. iOS开发 -------- transform属性(形变)

      一 transform属性 在OC中,通过transform属性可以修改对象的平移,比例和旋转角度 常用的创建transform结构体的方法分两大类 (1) 创建"基于控件初始位置&qu ...

  9. 在VS2013 使用C语言库函数,出现出现错误,提示使用不安全函数use _CRT_SECURE_NO_WARNINGS

    在VS 2013 中编译 C 语言项目,如果使用了 scanf 函数,编译时便会提示如下错误: error C4996: 'scanf': This function or variable may ...

  10. UVA1401 Remember the Word

    思路 用trie树优化dp 设f[i]表示到第i个的方案数,则有\(f[i]=\sum_{x}f[i+len[x]]\)(x是s[i,n]的一个前缀),所以需要快速找出所有前缀,用Trie树即可 代码 ...