当前位置: 首页 > 编程日记 > 正文

OO第一次总结

一.基于度量的程序结构分析

在进行分析之前,先解释一下以下几个缩写:

LOC:代码行数

CC:圈复杂度,反映了程序中if/while等判定条件的数量,越高意味着代码越可能质量低且难以测试、维护。

PC:方法参数个数

NOF:类的属性个数

NOPF:类的public属性个数

NOM:类的方法个数

NOPM:类的public方法个数

NC:类的子类个数

DIT:类的继承树深度

LCOM:类中内聚度的缺乏,越大意味着内聚度越差。

FAN-OUT:某个类引用其他类的次数

FAN-IN:类被其他类引用的次数

1、第一次作业

(1)设计思路

第一次作业使用了两个类:PolyItem用于管理多项式的每一项;PolyDerivation通过调用PolyItem类实现多项式合法性判定以及求导。在判断输入表达式合法性的同时,运用arraylist结构构造了一个每一项为PolyItem类的动态链表,对这个链表进行求导,最终得到多项式的导数,由于每一个PolyItem类维护系数和指数两个属性,因此在合并同类项的过程中可以通过判断指数是否相等而进行合并。

(2)结构分析

类图如下所示:

可见,PolyItem仅包含了对某一项求导、合并同类项的简单方法,而PolyDerivation则比较冗长的包含了多种处理。程序度量如下:

显然,与PolyDerivation相比,PolyItem中的方法行数少、复杂度低,比较容易测试,而PolyDerivation中方法CC有的高达11,这给程序的测试带来了一定困难。此外,PolyDerivation类的代码长度过长,达258行,表明类中可能存在比较多的冗余代码。由于第一次作业写的时候刚刚接触JAVA,基本是按照C的套路写的,类的划分并不好,也并没有用到继承(当时也并不知道继承是啥),因此程序层次并不深,却也导致了类中的内聚度比较好(大概是因为写成了C吧)。

2、第二次作业

(1)设计思路

第二次作业使用了三个类:PolyItem与第一次作业类似,用于管理多项式的某一项;PolyDerivation也与第一次作业的作用一致,用于识别整个多项式并完成求导;新增的Derivation类用于单独处理求导、合并同类项操作,目的是将不同类别因子的求导方法与多项式类分离。第二次作业的思路与第一次作业没有太大的区别,仅仅是在PolyItem类中多维护了sin(x)、cos(x)的系数这两个属性,合并同类项的方式也比较类似。

(2)结构分析

类图如下:

每个类及类中方法的度量如下:

可见,仍旧是多项式类的代码行数、方法行数、属性个数、复杂度比较高,其余两个类则比较简洁。由于求导类仅用于处理每一项的求导,项类则只用于管理合并同类项等粒度到项的操作,类内的内聚度比较好(由LCOM值较低可得),类间的耦合度较少。但是在第二次作业的时候,我显然没有领会到老师所提的代码重构的真正意图,我的这种架构在遇到第三次作业的之后完全崩溃,这告诉我代码的可扩展性也是很重要的,虽然在一开始设计时,我往往更关注本次作业所要完成的任务,而忽略了如何支撑更多、更复杂的功能。

 

3. 第三次作业

(1)设计思路

第三次作业明显比前两次难了很多,由于前两次作业我都没有考虑支持嵌套的问题,也没有使用继承、接口,我进行了完全的重构。如果说第二次作业是在第一次作业的基础上进行了扩展的话,第三次作业则是完完全全的重写。这次作业不仅在处理嵌套问题上难住了我,在最开始的多项式识别阶段就令我感到头疼。因为正则表达式不能支持递归识别,我最终采用了类似编译器的递归下降子程序处理方法,并在识别的过程中显式构造了一棵表达式树,这棵表达式树的叶子节点是形如x^2、sin(x)^2、cos(x)^2、常数这样的基本因子,树的中间节点是加、减、乘、嵌套等运算,由于在嵌套函数f(g(x))的求导过程中,sin(x)^2sin(factor)^2的求导方式没有本质的区别,因此,我将其合并成了同一类。表达式树上的每一类结点都维护一个属于自己的求导方式,树建立之后,通过调用根节点的求导方法即实现整个表达式的求导。

(2)结构分析

这次涉及的类比较多,类图如下所示:

                                                                                                                        

                                                                                                                                                                                                     

类的度量如下:

可见,使用继承之后,类的属性和方法有了明显的减少,但是有的类里出现了内聚度降低的情况,这表明类的划分并没有符合高内聚低耦合的原则。尽管使用了继承,但是继承树的层次相对比较小,大多为1层,结构比较简单。尽管第三次作业的架构难以实现优化的目标,但是通过将求导这个大问题拆成不同形式求导的小问题,简化了程序的结构,只要独立地思考每个类所要完成的功能,再最后进行简单的组装,就能实现求导功能。在这里,想简要的说明一下第三次作业中我关于优化的设计,因为并没有从整体上考虑优化的问题,我仅仅是在求导过程中进行了比较细节的优化,例如:在形如x^2这样的基本函数的求导过程中,如果系数是1,则直接得到x而非x^1;在加、减、乘、嵌套的求导时,如果乘法的因子中包含0,则直接得到0,而不进行额外的运算,如果涉及的各因子、项都是常数,则可以直接运算的到结果而不需要表达式输出等。尽管这些优化效果可能不是特别显著,但也起到了一定的作用。

 

二.程序中的bug分析

这三次作业中,前两次作业的设计都比较简单,主要的思想是在判断多项式合法性的过程中,构造了由项类组成的动态链表,再进行求导、合并同类项以达到优化的目的。第三次作业则采用了树的结构,在判断多项式合法性的过程中构造一棵表达式树,通过对根节点求导得到整个表达式的导数,并在每个类所维护的求导方法中进行力所能及的优化。显然,表达式树的结构要更具有可扩展性,并且能支持嵌套结构,且在实现的过程中,类之间的耦合度更低,只要实现好每个子类的求导,再将树构建好,即可完成整个表达式的求导。

由于表达式树的构建相对复杂一点,也比较容易产生bug。在构建的过程中,我主要遇到的是有关“不加括号导致运算顺序出错”的问题。在中间结点的求导过程中,由于左右两棵子树可能是因子、项、表达式中的任意一种,因此需要额外注意加括号的问题。例如:(sin(x) - x*cos(x))' = cos(x) - (cos(x) - x*sin(x)),如果不加括号,就会产生运算错误。

  • 在减法求导过程中,(f(x)-g(x))' = f'(x) - g'(x),为保证运算的正确性,减号右边需要加括号。
  • 乘法求导时,(f(x)*g(x))' = f'(x)*g(x) + f(x)*g'(x),由于项的性质,f(x)g(x)无需加括号,但是f'(x)g'(x)可能出现“一项变两项”的情况,因此,需要加括号。
  • 嵌套求导,f'(g(x)) = f'(g(x)) * g'(x),由于外层的f(x)函数是基本因子的形式,求导后不需要加括号,但是g(x)求导后可能出现“一项变两项”的情况,也需要加括号。

 

三.使用对象创建模式

第三次作业中,我应用的主要是继承,先构建一个基本的树节点,其中维护左右子树结点等属性以及求导、获取子树导数值等方法,而其子类则是通过重写求导方法实现不同函数求导的功能。在了解了工厂模式的相关内容之后,我将第三次作业进行了重构。

重构之后的类图大致为:

 

使用工厂模式可以很方便地根据需求创建不同类型的结点,并以求导函数为接口,实现不同类型函数的求导。

四. 总结

这三次递进式的求导作业让我经历了“如何写JAVA”->“如何尽量写出不像CJAVA”的过程,每次需求的增加不仅考验我们需求分析的能力,也考验了我们设计的能力。在写代码之前,先做好设计是很有用的,这不仅可以防止出现边写边改的情况,也有助于后期debug阶段更迅速定位bug

转载于:https://www.cnblogs.com/qrrr/p/10585975.html

相关文章:

python学习笔记(一)之入门

1、python的安装 官网下载.exe文件直接安装即可,在安装过程中选择加入环境变量,就不用在安装后再去增添环境变量了。 本文选择的是python3.6版本,没有选择2.7版本。 2、启动python解释器和运行.py文件 安装过程中选择创建桌面图标连接&#x…

丽水风光(二)—劫色“古堰画乡”

丽水风光 (二) 劫色古堰画乡 驱车从鸥江到古堰画乡大约二十分钟。一路由同学L老弟相陪,车刚停在江边,我就被美景陶醉,撇下老同学,旁若无人地与X兄一边卡嚓卡嚓去了,一副“…

爱情神话:庄妃用美色套牢洪承畴之谜

题记:庄妃,一个蒙古族的美丽,用她的美色俘获了大明王朝铁血将军洪承畴之心,不仅为满清开国立下了不世之功,而且也打造了一个千古流传的爱情神话。庄妃,孝庄文皇后,博尔济吉特氏,蒙古…

SQLServer2005数据库自动备份

一。SqlServer自动作业备份 1、打开SQL Server Management Studio 2、启动SQL Server代理 3、点击作业->新建作业 4、"常规"中输入作业的名称 5、新建步骤,类型选T-SQL,在下面的命令中输入下面语句 DECLARE strPath NVARCHAR(200)set strP…

JavaScript Array相关方法

JavaScript 标准内置对象 Array常用方法Array.prototype.every()Array.prototype.some()Array.prototype.filter()Array.prototype.find()Array.prototype.findIndex()Array.prototype.indexOf()Array.prototype.includes()Array.prototype.map()其他1. [JavaScript数组去重](h…

Web API之基于H5客户端分段上传大文件

http://www.cnblogs.com/OneDirection/articles/7285739.html 查询很多资料没有遇到合适的,对于MultipartFormDataStreamProvider 也并是很适合,总会出现问题。于是放弃,使用了传统的InputStream 分段处理完之后做merge处理。 前台分段规则 命…

对MySQL进行逻辑卷备份与恢复

ZRM 我之前我介绍过,这里就不多少了。以下是关于用mysql-zrm 来测试 基于LVM 逻辑卷管理的数据库全库备份。我这里用的是SUN 的VBOX 虚拟机来做的测试,基于Red Hat AS 5.3。1. 先建立逻辑卷。fdisk 我就不介绍了,这里演示下怎么用创建逻辑卷以…

医保退费主要流程

1.系统初始化Init GetInvoiceInfo with QryInvoice dobeginClose;ParamByName(DanJuID).AsString:edtDjid.Text;Open;vJiuZhenID:FieldByName(JiuZhenID).AsInteger;GetClinicInfo(vJiuZhenID);//获得就诊信息pnlDjrq.Caption:FieldByName(SerialNo).AsString;pnlSkr.Caption:F…

oo第一单元总结

第一次作业 第一次作业自己虽然很想向着面向对象的方向上写,但写出来还是很C语言式的程序。从头到尾扫描字符串,扫到加减号便认为接下来是一项,再用正则表达式去分情况匹配出这一项。用Hashmap来存储数据,方便合并同类项。最后套一…

npm run build打包失败

使用npm run build命令打包Angular项目时报错,错误信息如下: WARNING in budgets, maximum exceeded for initial. Budget 2 MB was exceeded by 3.33 MB.ERROR in budgets, maximum exceeded for initial. Budget 5 MB was exceeded by 340 kB. npm ER…

YII2 models非常好用的控制输出数据【重写Fields】

models里重写Fields真的很好用,用于分类、评论功能 列子:评论表models/Comment.php 1、关联商品表 2、获取父级(即管理员)评论 public function Fields()//添加parentComment自定义字段输出 { $fields parent::Fields(); $fi…

Visual studio 2005如何实现源码管理

转自CSDN Visual studio 2005如何实现源码管理(Visual Studio .Net团队开发)目录: 〇、 摘要一、 开发前的准备 二、 创建空的SourceSafe数据库 三、 新建项目并加入版本控制 四、 获取SourceSafe中的项目 五、 版本控制的几个概念 六、 版本控制项目的管理 七、 总…

error while loading shared libraries: libstdc++.so.5: wrong ELF class: ELFCLASS64

今天部署一个探针在运行的时候报了这样一个错:error while loading shared libraries: libstdc.so.5: wrong ELF class: ELFCLASS64 [rootdb152 rma_p_unix]# ldd xxxxlinux-gate.so.1 > (0x00dd7000)libstdc.so.5 > not found # 发现这边动态库找不着 这…

package.json 依赖包版本号

依赖包版本号格式:major.minor.patch major 为主版本号(大版本号),变化了表示有了一个不兼容上个版本的大更改。 minor 为次版本号(小版本号),变化了表示增加了新功能,并且可以向后兼容。 patch 为修订版本号,变化了…

.net下绘制统计图工具-请推荐

需要利用到行情、数据频道需要多种样式的表现形式,包括 饼图、柱图、折线图等等 重点是:展示效果好,开发效率高 以前用过dundas chart,不知道有没能生产flash的。 小弟初来乍到,还请给位不吝赐教 放两天置顶&#xff…

wireless(二维数组前缀和)

1 . 无线网络发射器选址(wireless.cpp/c/pas)【问题描述】随着智能手机的日益普及,人们对无线网的需求日益增大。某城市决定对城市内的公共场所覆盖无线网。假设该城市的布局为由严格平行的129条东西向街道和129条南北向街道所形成的网格状,并…

SQL Server 2000 从哪里看是哪个版本

有两种方法: 第一步:使用SQL语句查询 select version 查询结果如下: Microsoft SQL Server 2000 - 8.00.2039 (Intel X86) May 3 2005 23:18:38 Copyright (c) 1988-2003 Microsoft Corporation Personal Edition on Windows NT 5.1 (Build 2…

【洛谷p1313】计算系数

(%%%hmr) 计算系数【传送门】 算法呀那个标签: (越来越懒得写辽)(所以今天打算好好写一写) 首先(axby)k的计算需要用到二项式定理: 对于(xy&#…

CMD——ping及用其检测网络故障

Ping命令全称Packet Internet Grope,即因特网包探测器。通过调用ICMP(因特网控制报文协议),发送一份ICMP回显请求给目的主机,并等待返回ICMP回显应答。一般用来测试源主机到目的主机网络的连通性(只有在安装…

TSLint 规则

除了在全局配置中使用TSLint规则,还可以在文件中使用TSLint规则。 当不想修改全局配置中的TSLint规则时,可以在文件中使用以下注释规则标志对TSLint规则进行修改。 // tslint:disable —— 忽略该行以下所有代码出现的错误提示,可以在文件首…

Weblogic禁用SSLv3和RC4算法教程

weblogic在启用https时一样会报同WebSphere那样的一SSL类漏洞,中间件修复这些漏洞原理上来说是一样的,只是在具体操作上有着较大的区别。 1. weblogic禁用SSLv3算法 编缉$DOMAIN_HOME/bin目录下的setDomainEnv.sh,找到"JAVA_OPTIONS&quo…

转《两个个很形象的依赖注入的比喻》

何谓控制反转(IoC Inversion of Control),何谓依赖注入(DI Dependency Injection)?一直都半懂不懂,今天看到两个比喻,觉得比较形象。 IoC,用白话来讲,就是…

线程上下文设计模式

import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream;public class Test {public static void main(String[] args){ThreadLocalExample.test();} }/*21.2 线程上下文设计*/class ApplicationConfigurat…

自定义控件--基础2

Control类程序按控件的步骤: 呈现控件的步骤 1.RenderControl方法 代码如下: protected void RenderControl(HtmlTextWriter writer) { if(Visible) { Render(writer);}} 先判断Visible,然后进行Render.2.Render方法 public virtual void Render(HtmlTextWriter writer) { Rend…

input输入框为number类型时,去掉上下小箭头

input输入框type为number时&#xff0c;去掉上下小箭头&#xff0c;方式如下&#xff1a; <input type"number" ...><style>/* 在Chrome浏览器下 */input::-webkit-outer-spin-button,input::-webkit-inner-spin-button {-webkit-appearance: none;}/* 在…

数据库和数据仓库的区别

简而言之&#xff0c;数据库是面向事务的设计&#xff0c;数据仓库是面向主题设计的。 数据库一般存储在线交易数据&#xff0c;数据仓库存储的一般是历史数据。 数据库设计是尽量避免冗余&#xff0c;一般采用符合范式的规则来设计&#xff0c;数据仓库在设计是有意引入冗余&a…

我是主考官:两次弃用的变态笔试题

故事&#xff08;3&#xff09;&#xff1a;两次弃用的变态笔试题电话的沟通虽然不可能对一个程序员作全面的了解&#xff0c;但基本上能有一个比较概括的判断&#xff0c;这也许就是所谓的第一印象吧&#xff01;通过电话的初步沟通我对来面试的程序员已经有了初步的印象&…

[Swift]LeetCode901. 股票价格跨度 | Online Stock Span

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号&#xff1a;山青咏芝&#xff08;shanqingyongzhi&#xff09;➤博客园地址&#xff1a;山青咏芝&#xff08;https://www.cnblogs.com/strengthen/&#xff09;➤GitHub地址&a…

java基础===点餐系统

public class OrderMsg {public static void main(String[] args) throws Exception { /** * 订餐人姓名、选择菜品、送餐时间、送餐地址、订单状态、总金额 * 01.创建对应的数组 * 02.数组的初始化 * 03.显示菜单 * 04.根据用户的选择进去指定的模块 */ String[] names new S…

HTML页面中使两个div并排显示

在HTML中实现两个div并排显示&#xff0c;方法如下&#xff1a; 方法1&#xff1a;设置float浮动对需要并排显示的div设置样式&#xff1a;style"float:left;" <div style"float:left;">div1</div>方法2&#xff1a;设置div为行内样式对需要并…