前言

  经过了对于面向对象程序设计的一个月的学习,我初尝了JAVA以及面向对象程序的魅力。经历了三次难度逐渐加大的课后编程作业,我对于工程化面向对象编程以及调试有了深刻的认识与颇多感想。我写下本篇文章以总结分析这一个月的课后作业的完成情况。


作业总结与分析

多项式加减运算

(1)题目简述:

  实现一元多项式的加减运算

(2)程序设计:

  Class设计:

  • PolyCul类:进行多项式输入,多项式计算调度,多项式输出。
  • Poly类:存储多项式信息,进行多项式计算。
  • Item类:存储单个项的信息,进行项的计算。

  程序规模:

  

  程序类图与类演示图:

  

  

(3)程序分析:

  程序的结构化程度(ev)、设计复杂度(lv)和判定结构复杂度(v)情况较好,只有负责输入字符串合法性识别以及多项式组插入的方法的复杂度较高。其他方法的复杂度都处于正常的范围内。输入字符串合法性识别方法复杂度高的原因主要是最初设计时对于指导书的输入需求的理解不够充分,导致了一开始设计的识别算法无法全面地处理输入字符串,使得编程完成后要补充新的判断分支,导致方法代码冗余。多项式组插入方法复杂度高的原因是每次调用方法时需要遍历已有的有序多项式组、判断同次多项式、寻找新多项式在其中的位置扩展多项式组并插入新多项式。

  量化分析结果如下:

  

(4)出现的问题:

  Bug:”-0”字符处理不当。

  在最初的设计中并未考虑输入”-0”的需求,处理这一需求的代码是在程序完成后补充的。由于补充代码时仅考虑了处理”-0”,所以直接使用字符串替换将”-0”替换成了”+0”,导致了程序能够识别以”-0”为前缀的数字,如”-001”。而负数输入是非法的。

  从整个程序来看,该问题导致了程序内会存在非法的数值,虽然就指数计算来看负数引入并不会导致数学上的错误。但由于程序内其他的使用该变量的方法默认处理正数,而不存在处理负数的措施,对于输入判断模块方法的正确性有一定的依赖性。出现入口的错误会使得程序存在崩溃的隐患。

  相关代码:

private void str_input() {
Scanner s = new Scanner(System.in);
this.str = s.nextLine().replaceAll(" +", ""); //去除空格。
this.str = str.replace("-0","+0");//去除-0.
s.close();
}

简单电梯调度

(1)题目简述:

  实现简单(FAFS)电梯调度系统。

(2)程序设计:

  Class设计:

  Sheduler类:完成请求的输入及处理,根据请求队列调度电梯、输出电梯运动情况。

  ReqQueue类:实现对请求队列内请求的处理,实现重复请求的识别与剔除。

  Request类:格式化存储请求信息。

  Lift类:根据调度类改变电梯的位置、运动情况以及电梯内各按钮的状态(未被使用)。

  Floor类:记录每层楼按钮的状态(未被使用)。

  程序规模:

  

  程序类图与类演示图:

  

  

(3)程序分析:

  程序的结构化程度(ev)、设计复杂度(lv)和判定结构复杂度(v)情况一般。获取下一执行请求的方法的复杂度最高,此外请求队列遍历操作的相关方法的复杂度也较高。在获取下一执行请求的方法中需要对下一请求的同质性进行判断,导致方法中存在大量的判断语句的嵌套,产生了较多的判断路径。此外,判断语句处于循环中,使得复杂度提高。出现这一情况主要是由于最初的设计不够完善,在编程的过程中不断添加路径,最后使判断逻辑关系比较混乱,也就是模块判断复杂度的提高。其他方法主要由于非结构化代码较多。

  量化分析部分结果如下:

  

  

(4)出现的问题:

  Bug:输入数字范围限制错误。

  指导书要求输入数字范围为四字节,而程序中限制的是int型变量能表示的非负数。这主要是对于指导书的要求理解错误导致的。该错误对于程序正常运行的影响较小。

  Bug:”&”与”&&”运用错误。

  这一错误的表现形式是当输入的请求存在同质请求时程序会崩溃。经过分析最后确定了是以下代码导致程序崩溃:

if(next_req.get_req_kind().equals("FR") & next_req.get_FR_operator().equals(running_req.get_FR_operator())) {
  next_req.set_fesibility(false);
System.out.println("#第" + next_req.get_input_line() + "个请求与第" + running_req.get_input_line() + "个请求行为相同!");
continue;
}

  该段代码应当更改为:

if(next_req.get_req_kind().equals("FR") && next_req.get_FR_operator().equals(running_req.get_FR_operator())) {
next_req.set_fesibility(false);
System.out.println("#第" + next_req.get_input_line() + "个请求与第" + running_req.get_input_line() + "个请求行为相同!");
continue;
}

  “&&”与”&”的区别在于后者会对所有的表达式进行运算,最后取逻辑与得到结果;而前者会顺序对表达式进行运算,若遇到了一个表达式为false则不会对后面的表达式进行运算。而在上面代码中,如第一个表达式为false时,第二个表达式中的方法调用是非法的,若运行就会使程序崩溃。”|”和”||”的原理相同。

  这段代码于程序的其他部分的代码相关性不高,只依赖于Request类的内部结构。电梯请求与楼层请求在格式上的不同使得该段代码需要考虑二者的特性与共性来产生判断分支。出现这一问题主要由于对于其特性的考虑不够全面。

优化电梯调度

(1)题目简述:

  实现具有捎带功能的电梯调度系统。

(2)程序设计:

  Class设计:

  Sheduler类:实现简单调度功能,为前一作业的代码。

  AlsSheduler类:完成请求的输入及处理,根据请求队列调度电梯、输出电梯运动情况。

  ReqQueue类:实现对请求队列的基本处理。

  ExeQueue类:实现对执行请求队列的基本处理。

  QueueHandleInterface接口:规范化请求队列处理的方法。

  Request类:格式化存储请求信息。

  Floor类:记录每层楼按钮的状态(未被使用)。

  Lift类:根据调度类改变电梯的位置、运动情况以及电梯内各按钮的状态(未被使用)。

  LiftInterface类:规范电梯类的接口。

  程序规模:

  

  程序类图与类演示图:

  

  

(3)程序分析:

  程序的结构化程度(ev)、设计复杂度(lv)和判定结构复杂度(v)平均情况一般,但有部分的复杂度相当高。其中主要是调度运行方法以及输入处理的一系列方法。

  在调度运行方法中存在一个循环来模拟时间的流动,并且在每一时间帧中有大量条件判断构建状态机来实现电梯的调度。复杂的逻辑判断导致这一方法的结构十分冗杂,加大了代码的规模,大大提高了复杂度。出现这一问题的主要原因是设计的调度算法未进行优化,较为粗糙,在功能上未对代码进行归类,按照面向过程的思路堆砌判断条件。

  在输入处理方面,相较前两次作业,本次作业的表现并不好。经过后期的分析,在这一部分出现了伪面向对象式的代码。在相关的一系列方法中调用深度过深,实质上是将一个方法分割为多个私有方法碎片,相互耦合的现象较严重。此外,在这次作业对上次作业进行继承后发现输入处理部分的代码应当分离成单独的类,而不应当归属于调度类。

  量化分析部分结果如下:

  

  

(4)出现的问题:

  在功能方面尚未检测出问题,但在程序结构的设计方面上暴露出了许多的缺陷。主要体现在:部分类的功能冗余、调度算法需要优化、方法设计不妥当。


心得体会

  • 捕捉字里行间的需求

  在这几次的编程作业中,我最先感受到的是充分理解需求的重要性。每一次作业都有一个篇幅较大较为详细的指导书。指导书对于程序需求与功能的描述或多或少有些模糊或者易产生歧义的地方,这对于程序的架构带来了一定的困难。但相较于现实工作中遇到的客户的需求描述,指导书中的描述已经具体了许多。而我们所需要的就是从描述需求的自然语言之中提取出关键的信息,在零散的信息中寻找逻辑上的练习,并建立模型完成程序的架构

  在第一次作业中,需求的捕捉并不算太困难,主要在输入合法性的判断上。而在后两次作业中,需求很明显就复杂了许多。由于指导书的篇幅较长,为避免遗忘,我在通读指导书的同时将发现的关键信息按条记录下来。在多次阅读指导书后,我再将提取到的信息按照其所属的功能部分进行分类,分析实现每个需求所需要的代码或算法。

  此外,在设计时还应当考虑到文中未提及的那些“言外之意”,使程序能够应对指导书中未提及的需求与输入。这需要设计者对需求进行适当的外延与扩展,扩大程序的包容性、兼容性。这在现实的程序设计中具有相当重要的意义。

  • 结构设计模块化

  面向对象编程最重要也是最困难的部分就是设计程序的结构:根据程序需要的操作和数据,将程序分离封装成不同的功能模块,每个模块的聚合度要高,各个模块之间的交集要小。在设计程序时应当自顶向下地思考。若要实现总的需求,程序要具有哪些功能,需要拥有那些数据,需要对数据进行什么操作?根据这些问题以及从指导书捕捉到的信息,我们就能够大致地列出一个清单,再根据其中的聚合关系就能画出程序的结构(类)图。之后在优化的时候还可对设计进行微调,以获得分离度更好地类设计。

  在这三次作业中,我在程序结构设计上表现一般。在编写的程序中已经有了聚合度比较好一些模块,但在将程序建模成类图后同推荐的设计比较还是能发现许多的不足。我在输入识别处理模块的设计上就有失妥当:在这几次作业中我都将这一模块并入了调度模块。这一设计并不符合模块化设计的理念。输入处理操作应当封装成一个独立的模块专门进行相关的操作。而我将其并入调度类,就会使调度类过于繁杂,过于扩大其功能,提高了复杂度,降低了可维护性。从第三次作业继承第二次作业时就能明显感觉到修改代码的工作量较大。

  • 简化方法规模

  在方法的设计上应当尽量精简每个方法的代码量,使每个方法能高效地完成单一的一个任务。应当严格地控制每个方法功能、判断分支、调用深度和代码规模对于降低程序的调试与维护难度有着不错的效果。在我编写的这几个程序中,方法精简的部分最容易进行修改,也最不容易出现问题;出现问题的地方主要是判断分支较多的方法。

  要控制方法规模主要需要对程序中的各个操作进行准确的提炼,获取其中核心的原子操作形成相应的方法。分析我程序中规模较大方法可以发现,这些方法都包含了至少两种操作,一个方法的功能过于繁杂。这样就导致我维护、修改代码时遇到了较多困难,并且容易产生不易发现的问题。

  • 系统化测试代码

  由于输入情况的多样性,简单的功能性测试是远不够的。按照老师课堂的要求,我在测试阶段构建了错误分支树。顶层按照正常功能与异常处理进行分叉,逐渐向下延伸产生错误分支,并为每个分支构造了一至两个测试输入。最后用构造的测试集进行代码测试。通过这样一个比较系统化的测试方式,我比较迅速准确地锁定了存在问题的代码。得益于结构化的代码结构,我也能够较快地优化程序。

OO学习总结与体会的更多相关文章

  1. 【OO学习】OO第四单元作业总结及OO课程总结

    [OO学习]OO第四单元作业总结及OO课程总结 第四单元作业架构设计 第十三次作业 第十四次作业 总结 这两次作业架构思路上是一样的. 通过将需要使用的UmlElement,封装成Element的子类 ...

  2. 【OO学习】OO第三单元作业总结

    [OO学习]OO第三单元作业总结 第三单元,我们学习了JML语言,用来进行形式化设计.本单元包括三次作业,通过给定的JML来实行了一个对路径的管理系统,最后完成了一个地铁系统,来管理不同的线路,求得关 ...

  3. OO学习体会与阶段总结(多线程程序)

    前言 在最近一个月的面向对象编程学习中,我们进入了编写多线程程序的阶段.线程的创建.调度和信息传递,共享对象的处理,线程安全类的编写,各种有关于线程的操作在一定程度上增加了近三次作业的复杂度与难度,带 ...

  4. OO学习体会与阶段总结(设计与实现)

    前言   在最近的一个月的课程中,笔者对于规格化编程进行了深入的学习.运用面向对象抽象思想对编写的程序进行过程抽象.异常处理.数据抽象.类的层次规格与迭代等等规格设计,使得程序结构化程度提高,具有更好 ...

  5. OO学习体会与阶段总结(测试与论证)

    前言   随着期末的到来,对于面向对象程序设计课程的学习也迎来了尾声.在最后一个月的从课程中,笔者对于面向对象程序规格实现层面的单元测试.正确性论证以及使用UML图描述程序的设计进行了深入的学习.通过 ...

  6. 【OO学习】OO第二单元作业总结

    OO第二单元作业总结 在第二单元作业中,我们通过多线程的手段实现了电梯调度,前两次作业是单电梯调度,第三次作业是多电梯调度.这个单元中的性能分要求是完成所有请求的时间最短,因此在简单实现电梯调度的基础 ...

  7. OO学习最终总结

    0.前言:本次主要是针对第三阶段的三次作业以及整个课程学习的总结,这三次作业主要是针对对程序进行重构使得程序可以对功能进行扩展的训练以及对类的设计,所以在此阐述在练习过程中的问题以及感悟. 1.作业总 ...

  8. 20165221 JAVA第一周学习心得及体会

    JAVA入门的理论学习 在JAVA2使用教程的网课学中,分为以下几个模块讲解的 JAVA的地位 JAVA的特点 安装JDK(Java Develepement Kit) Java程序的开发步骤 简单的 ...

  9. 学习Hibernate的体会

    这个学期老师让我们做一个系统(服务器和客户端),语言自选,我也随大家开始学习java web 和android . 下面是我自学的一些体会和遇到的问题. 关于jar包. jsds.jar javasi ...

随机推荐

  1. MHA实践操作

    1.MHA部署解读: 1.1MHA Manager可以部署在一台slave上.MHA Manager探测集群的node节点,当发现master出现故障的时候,它可以自动将具有最新数据的slave提升为 ...

  2. Hdu4952 - Number Transformation - 数论(2014 Multi-University Training Contest 8)

    寻找1~k内i的倍数.则这个数能够看成i*x,则下一个数为(i+1)*y,(i+1)*y>=i*x,那么能够推出.y=x-x/(i+1); 那么当x<i+1时,y==x.之后的循环也不会改 ...

  3. Hadoop应用开发,常见错误

    错误1:在windows执行mr Exception in thread "main" java.lang.UnsatisfiedLinkError: org.apache.had ...

  4. fdisk与parted分区

    我所接触的linux分区分为两种,一种是使用fdisk分区,另外一种是parted分区.前者是针对MBR模式分区的,后者是针对GPT模式分区的 fdisk分区: fdisk -l ---->查看 ...

  5. mysql索引和外键

    innodb外键: 1.CASCADE:从父表删除或更新会自动删除或更新子表中匹配的行 2.SET NULL:从父表删除或更新行,会设置子表中的外键列为NULL,但必须保证子表列没有指定NOT NUL ...

  6. HTML5知识点汇总(1)

    HTML5 1.html5是什么 万维网的核心语言.标准通用标记语言下的一个应用超文本标记语言(HTML)的第五次重大修改.-------h5并不是一门新的语言,而是html语言的第五次修订. 2.h ...

  7. WPF的IsSynchronizedWithCurrentItem属性

    如果两个控件都绑定到同一个源(ObservableCollection)集合视图时,该对象会自动绑定到该视图的 CurrentItem.请注意,CollectionViewSource 对象会自动同步 ...

  8. scribe日志系统安装笔记

    版本历史 2011-02-12 17:36:57 完成文章2011-02-23 10:49:12 更新,修正部分文字 目前web访问日志为crontab定时清空,而且负载均衡后,访问随机分配到一台服务 ...

  9. 20155239 2017-11-19 实现mypwd(选做,加分)

    20155239 2017-11-19 实现mypwd(选做,加分) 题目和要求 学习pwd命令 研究pwd实现需要的系统调用(man -k; grep),写出伪代码 实现mypwd 测试mypwd ...

  10. Spring restTemplate

    什么是RestTemplate RestTemplate是Spring提供的用于访问Rest服务的客户端,提供了多种便捷访问远程HTTP服务的方法,能够大大提高客户端的编写效率.   项目中注入Res ...