我永远喜欢着OOP——第一次总结


一、三次作业总结分析

1. 第一次作业

1.1 作业分析

第一作业主要是给我们引入了一个对于非法输入处理的思想,包括第一次上机,都一直围绕着一个全新的主题,就是非法输入处理,而对于这次作业本身,其实难度并不是很大,甚至用纯C也不会有很大的工作量,但是引入了一个这样一个重要思想笔者觉得是学到很多的

1.2 程序架构

说起第一次作业,笔者其实是有为第二次作业做准备的(但是看起来准备的并不合格),在第一次作业中笔者还专门准备了一个虚基类来准备继承其他的项(因为怕操作失误删了),以方便在第二次作业如果加入其他的函数,就直接加上一个新的子类,然后上层逻辑用利用多态,根本不用改(事实证明是我想少了)。

直接上UML图吧(先让我去git clone 一下)

可以看到,看到每个类的方法很多,不过细看可以看出来很多其实这主要是方法模块化的结果。

首先是关于错误处理和输入规范化,笔者单独实现了一个Parser解析类来完成这个工作,利用正则分割和匹配每一项,在遇到非法输入即抛出异常,有顶层类捕获并输出WF

然后就是求导部分,因为只有加法,所以只需要表达式调用每个项的求导即可完成求导

最后是化简,也就是优化,在本章作业里,优化都是一个让我觉得很难受的地方,也不一定说每个优化有多么复杂的逻辑或是算法,但是更多的给我的感觉是,从整理到求导整个过程像是一个整体,而优化就像是没有关系的一件事情硬插在了里面。

不过现在静下心来思考,其实,优化不应该被放在任何一个因子、项、表达式类里面,其实,笔者觉得应该装饰者模式来处理也许会更好,每种优化作为一个装饰者,然后将项、表达式、因子传入,然后再得到化简后的结果,这样的组织首先不会导致化简逻辑和运算逻辑混为一谈,两件事情高度耦合,错误就很容易发生(笔者本人也是深受其害,以至于Bug修复的时候只需要注释掉simplify()函数就可以修复绝大多数同质Bug),所以还是回到了高内聚低耦合的话题上,这件事情应该是设计阶段要仔细思考的一件事。

所以也可以看到,我的项和表达式里面充斥着大量的和项与表达式运算无关的方法,他们也严重违反了单一职责原则

Class CBO DIT LCOM NOC RFC WMC
Arithmetic 3.0
Parser 1.0 1.0 1.0 0.0 21.0 13.0
Poly 2.0 1.0 1.0 0.0 39.0 23.0
PowerItem 2.0 1.0 4.0 0.0 26.0 29.0
Solution 2.0 1.0 1.0 0.0 16.0 3.0
Total 68.0
Average 1.75 1.0 1.75 0.0 21.0 17.0

从度量中也可以看到整体复杂度其实还是不高的

2. 第二次作业

2.1 作业分析

第二次相对于第一次,求导规则更加复杂,数据如何组织是一件比较麻烦的事情,由于当时笔者没有将常数作为单独一项来处理,所以导致在优化合并的时候,提取系数极其困难

2.2 程序架构

直接上类图,咱们看图说话

很庞大,但是其实就是因子继承虚基类,然后所有承在一起的因子构成一个所谓的Box,Box中用HashMap来维护三项,主体逻辑跟上一次完全相同,但是化简逻辑复杂了很多,从图中也可以看到有很多化简函数放在了里面,让人看不懂,这也是这三次作业的败笔所在,没有把化简功能分离出来,这样不仅不利于测试化简功能,而且程序的未知行为无法估测,这也是这样测试中出现Bug的一个十分重要的原因

下面给出程序的度量

Class CBO DIT LCOM NOC RFC WMC
Constant 1.0 0.0 0.0 0.0 0.0 0.0
ItemType 4.0 1.0 2.0 2.0
Solution 4.0 0.0 1.0 0.0 11.0 4.0
ItemFactory 6.0 0.0 1.0 0.0 5.0 9.0
TirgoItem 4.0 1.0 2.0 2.0 11.0 10.0
SinItem 7.0 2.0 5.0 0.0 17.0 11.0
CosItem 7.0 2.0 5.0 0.0 17.0 11.0
Item 7.0 0.0 8.0 2.0 15.0 12.0
Parser 4.0 0.0 1.0 0.0 10.0 13.0
Poly 2.0 0.0 1.0 0.0 17.0 25.0
PowerItem 6.0 1.0 8.0 0.0 21.0 29.0
ItemBox 9.0 0.0 1.0 0.0 22.0 44.0
Total 170.0
Average 5.083333333333333 0.5454545454545454 2.8333333333333335 0.36363636363636365 11.692307692307692 14.166666666666666

可以看到,由于PolyItemBox类中集合了过多本不该属于他们的方法,所以导致这两个类的复杂度很高,最终的Bug也是出现在这两个类的协作中

3. 第三次作业

3.1 作业分析

这次的作业看起来改动很大,其实仔细分析可以发现,只是新增了一个嵌套功能,也就是说,如果保证嵌套的内容没有问题,那么整个程序的逻辑和第二次作业基本是一致的,我也是按照这个思路来组织,并根据指导书给出的因子、项、表达式这样的分层结构来实现的设计

3.2 程序架构

基本就是按照指导书给出的三层结构来实现的设计,下面给出UML图

结构很清晰,容我再次痛斥一次我这种肮脏的优化设计,耦合度真的很高,无法测试,导致系统存在大量的不确定性,正确性无法保证的同时,还无法单独调试改错,实在丑陋

Class CBO DIT LCOM NOC RFC WMC
ExceptionUtil 1.0 1.0 1.0 0.0 5.0 1.0
Main 4.0 1.0 1.0 0.0 12.0 2.0
PowerFactor 5.0 2.0 2.0 0.0 18.0 9.0
NumFactor 7.0 2.0 2.0 0.0 17.0 9.0
Factor 7.0 1.0 4.0 5.0 20.0 12.0
FactorFactory 7.0 1.0 1.0 0.0 9.0 13.0
ExprFactor 5.0 2.0 4.0 0.0 22.0 15.0
CosFactor 6.0 2.0 1.0 0.0 36.0 19.0
SinFactor 6.0 2.0 1.0 0.0 35.0 19.0
Term 13.0 1.0 1.0 0.0 51.0 49.0
Expr 3.0 1.0 3.0 0.0 61.0 63.0
Total 211.0
Average 5.818181818181818 1.4545454545454546 1.9090909090909092 0.45454545454545453 26.0 19.181818181818183

可以看出,底层的模块的复杂度还较为良好,而上层的模块,也就是项和表达式,由于过多的化简逻辑掺杂其中,导致这两个类的复杂度很高,是十分糟糕的情况

二、关于Bug

1. 我的Bug

笔者在第二次和第三次都出现了Bug,而且情况很类似,都是一个几行代码就能修复但是却很致命的Bug,我觉得原因有下面几点:

  • 思路不够清晰,或者说由于模块耦合过度导致思路混乱
  • 数据组织方式有问题,数据的组织形式往往是在设计时针对求导来设计的,而往往忽略了优化部分,然而又没有采用新的组织,导致最终出现问题或者化简困难
  • 本身算法水平较差,算法效率不够

所以我觉得,在设计一个程序的时候,首先,应该保证良好的模块间解耦,从而能够让思维集中而不用去一直全局考虑,其次,就是要合理组织数据,如果要完成的两件事情有各自的较优数据组织方式,那么重新组织数据也不失为一种方法

2. 别人的Bug

关于如何发现别人的Bug,我从两个角度说吧

出于行业内的代码审查和代码走查方式:

这种方式强调看代码逻辑,也就是白盒测试,在看代码的同时不断提出疑问,然后从这些疑问中寻找可能存在的bug,黑盒测试在这里只起辅助验证作用。

然而,在现有的游戏模式下,首先,你要面对的是六七份代码,每份的代码量都在千行左右,而且有的代码的可读性又比较差,毕竟没有统一的设计规范,这种方法基本不可行,毕竟这种方法在企业中的效率也就只是几个人两个半小时几百行代码的样子

所以,萌生了一种很没趣的方式——评测机玩法

我也叫它摇奖玩法,就是通过自己定义一个生成逻辑,然后模拟评测机去一直测测测,什么时候测到了就算捞到了,这个方法主要的效果是会给编程人员较大的压力和动力去完善自己的代码,对于评测人员,应该可以提高编写脚本的能力,可谓收获颇丰呢

三、关于设计模式

既然说到设计模式了,就简单提一下

对于本次作业,我觉得有下面这两种模式都是比较推荐的:

  1. 工厂模式,借用工厂模式将因子的生成逻辑(判断 + 生成)封装,代码看起来会很简洁,也可以看到我从第二次作业,类图里面就多了一个FactorFactory
  2. 装饰者模式,这个主要用于解决化简优化问题,每个化简逻辑可以被定义为一个装饰者,然后将求导的结果一层层装饰,最终获得优化结果,这个模式是笔者前两天才想起的,没有用到作业中也是可惜了

我永远喜欢着OOP——第一次总结的更多相关文章

  1. [洛谷P3987]我永远喜欢珂朵莉~

    [洛谷P3987]我永远喜欢珂朵莉~ 题目大意: 给你\(n(n\le10^5)\)个数\(A_{1\sim n}(A_i\le5\times10^5)\),\(m(m\le5\times10^5)\ ...

  2. 我永远爱着OOP——第二单元作业总结

    第二单元的电梯真是愉♂快呢,多线程编程作为java编程OOP中的重要组成部分,通过这一个单元的学习,我也是有了很多全新的认识 那么下面就先例行一下公事 三次作业分析 第五次作业 设计分析 实现的电梯是 ...

  3. OOP第一次博客作业

    一.关于Java&&面向对象 本学期刚开始进行Java的学习,也是刚开始了解面向对象,目前也就学习了三四周的样子,期间进行了三次作业,我感觉到Java的语法和c语言中的有许多相似之处, ...

  4. 洛谷P3987 我永远喜欢珂朵莉~(set 树状数组)

    题意 题目链接 Sol 不会卡常,自愧不如.下面的代码只有66分.我实在懒得手写平衡树了.. 思路比较直观:拿个set维护每个数出现的位置,再写个线段树维护区间和 #include<bits/s ...

  5. 我永远喜欢我的偶像 KIKU

  6. 【木德木作杯楼市达人秀NO.28】南湖买房故事

    应得意版主的邀请,我也来写写我的买房故事,虽然过程没有别人那么惊心动魄,但是毕竟是自己人生中非常重要的一件事情,就像恋爱一样,情话永远没有情书好,我也借此纪念一下这段短暂的时光.其中会涉及到本人对一些 ...

  7. 【计算机网络】应用层(一) HTTP

      HTTP报文 HTTP报文是HTTP应用程序间发送的数据块,它由三部分组成:起始行(start line),首部(header)和主体(body),如下图所示:   从分类上,报文又可以分为请求报 ...

  8. System.Collections 学习

    public interface IEnumerator { object Current { get; } bool MoveNext(); void Reset(); } public inter ...

  9. BZOJ 3143 游走 | 数学期望 高斯消元

    啊 我永远喜欢期望题 BZOJ 3143 游走 题意 有一个n个点m条边的无向联通图,每条边按1~m编号,从1号点出发,每次随机选择与当前点相连的一条边,走到这条边的另一个端点,一旦走到n号节点就停下 ...

随机推荐

  1. Android学习笔记(2):build.grandle的常用设置

    1 > java开发中有两个大名鼎鼎的项目构建ANT.Maven. 2 > Google推荐使用的Android Studio是采用Gradle来构建项目的.Gradle是一个非常先进的项 ...

  2. 第一课:Python入门(笔记)

    一.变量 1.什么是变量 #变量即变化的量,核心是“变”与“量”二字,变即变化,量即衡量状态. 2.为什么要有变量 #程序执行的本质就是一系列状态的变化,变是程序执行的直接体现,所以我们需要有一种机制 ...

  3. unigui ShowModal、MessageDlg

    procedure Calback(Sender: TComponent; AResult: Integer);procedure TForm.Calback(Sender: TComponent; ...

  4. 几分钟几张图教你学会如何使用UML

    很多初次接触UML的朋友们可能会感觉它各种各样的线条.关系.描述等晦涩难懂.本篇文章简单介绍了一下其中几个图,用最朴实的语言结合上图片来让你一眼就能理解他们,如果您在阅读的过程种发现错误之处恳请您在评 ...

  5. Web前端-Vue.js必备框架(二)

    Web前端-Vue.js必备框架(二) vue调式工具vue-devtools 过滤器:vue.js允许你自定义过滤器,可被用作一些常见的文本格式化. mustache插值和v-bind表达式. vu ...

  6. 简单读!Mybatis源码(一)一条select的一生

    工具除了会用,还应该多做点.我觉得使用一个软件工具(开源类),一般会经历几个步骤: 1. 通过wiki了解大致作用,然后开始码代码: 2. 系统性地学习其特性,找出可能需要的点,用上去: 3. 通过阅 ...

  7. java常见面试题及部分答案

    1.Redis常见的存储数据类型 list(列表类型) set(集合类型) zset(有序集合类型) string(字符串类型) hash(散装类型) 2.log4j的级别 debug:日志的最低级别 ...

  8. 意料之外,情理之中,Spring.NET 3.0 版本发布-

    意料之外,情理之中,Spring.NET 3.0 版本发布- 备受社区和企业开发者广泛关注的Spring.NET在上周发布了3.0版本,并且目前已经保持着持续的更新,让我们一起来看一看他究竟发布了哪些 ...

  9. js对象之XMLHttpReques对象学习

    背景:业务需求是,一个前端(手机和浏览器)HTML页面中有图片,按钮......,需要统计用户点击图片或者按钮的次数. 前端实现:通过一个js来统计HTML页面中所有的图片和按钮对象,并给每个对象赋予 ...

  10. H5拖动实现代码

    原理以后有空再说现在嘛先上代码.... ;} html,body { width: 100%; height: 100%; ; } #dragBoxContainer{ width: 150px; p ...