OO学习总结与体会

前言

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

 


 

 

做业总结与分析

多项式加减运算

 

(1)题目简述:

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

 

(2)程序设计:

 

  Class设计:架构

  • PolyCul类:进行多项式输入,多项式计算调度,多项式输出。

 

  • Poly类:存储多项式信息,进行多项式计算。

 

  • Item类:存储单个项的信息,进行项的计算。

 

  程序规模:模块化

  

 

  程序类图与类演示图:学习

  

  

(3)程序分析:

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

  量化分析结果以下:优化

  

 

 

(4)出现的问题:

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

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

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

  相关代码:

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)出现的问题:

  在功能方面还没有检测出问题,但在程序结构的设计方面上暴露出了许多的缺陷。主要体如今:部分类的功能冗余、调度算法须要优化、方法设计不稳当。


 

心得体会

  • 捕捉字里行间的需求

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

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

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

  • 结构设计模块化

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

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

  • 简化方法规模

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

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

  • 系统化测试代码

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

相关文章
相关标签/搜索