OO第一次博客作业

OO Unit1 总结

​ 前三次作业以多项式求导为核心,每次作业在上一次基础上加大难度,在完成这些作业以后,我对于面向对象的设计方法、思想迭代开发的模式有了一定的理解,以下是对第一单元三次作业的分析和一些心得体会。

第一次作业

  • task:实现简单多项式的求导,因子仅为带符号整数与幂函数。

  • 类图

    设计思想:由于第一次因子较为简单,我采用了HashMap类型对单个项进行建模,设计一个多项式类来完成对多项式的存贮和输出,一个求导类用来对多项式进行求导。

    优点

    • 多项式表达简单。
    • 将求导逻辑与多项式构建分离,层次清楚。

    缺点

    • 缺乏可扩展性。
    • 求导的操作仍然与具体的多项式形式相关,抽象性不够。
  • 复杂度分析

    ​ 多项式构建方法,求导方法的复杂度均较低;但是多项式输出方法的复杂度过高,原因是将优化放在了输出的过程中,导致输出部分的逻辑过于庞大,而且带有众多的分支结构,这样虽然没有超过代码风格规定的代码行数,但是仍然造成了可读性、代码结构化程度的降低。

  • 耦合度分析

    ​ 虽然第一次设计只有两个类,但是相互依赖程度较强,求导完全依赖多项式的具体表达形式,没有较好实现类之间的解耦。


第二次作业

  • task:在第一次作业的基础上,增加了简单三角函数的求导,并且允许复合项的出现。

  • 类图

    设计思想:设计思想与第一次类似,由于因子有且仅有三种类型,而且不存在嵌套情况,因此使用三元组(a,b,c)来表示任意一项的变量部分,加上每一项的系数就构成了一项;求导利用公式 $(abc)' = a'bc + ab'c + abc';​$ 这种定式的方法来完成。

    优点

    • 多项式表示方法简单。
    • 求导方法简单。
    • 层次上体现了多项式与项的区分。

    缺点

    • 三元组表示的多项式在优化上较为困难。
    • 由于多项式的表示、求导均为定式方法,在扩展上有极大的困难。
  • 复杂度分析

    ​ 方法数量较第一次作业来增大了很多,每个方法的长度适中,但是在多项式输出、输入处理方面的逻辑仍然非常庞大,分支结构过多,不利于代码结构的维护。

  • 耦合度分析

    Term类和Polynomial类之间解耦较好,各自负责处理各层的逻辑,后者由前者组合而成;但是PolynomialDerivation类与Polynomial解耦较差,求导方法抽象度低。


第三次作业

  • task:在第二次作业基础上增加了因子的嵌套规则。

  • 类图

设计思想:此次作业的难度较前两次有明显提高,想用一个固定模式来表达多项式和求导是不现实的,必须要寻求新的抽象方式。仔细分析多项式构成的结构,是由各类基础因子加上不同的运算规则(+-*嵌套),每种因子与每种运算都是一个单独的单元,而且其求导的方法都是独立的,因此抽象出ArithObject类(有常量、幂函数、sin、cos四个子类)和ArithOperator类(有+-*嵌套四个子类),设立统一的求导接口,由Node类实现,其他类重写。最后,将输入处理逻辑单独划分为一个类。

优点

  • 层次分明,逻辑清晰。
  • 求导实现极为简单,写好各个子类的求导方法后,实际求导过程只要按照表达式树自底向上依次求导即可完成。

缺点

  • 优化极为困难

  • 复杂度分析

    ​ 这一次各个方法之间的划分极为清楚,每个方法的长度适中,没有过多的分支结构,在写代码过程中进行了多次的划分方法切割,将一些重复的、逻辑相对独立的代码段重新写为方法。

  • 耦合度分析

    ​ 本次设计的耦合度极低,在表达式方面,先定义父类Node类,然后由子类去具体实现不同功能,层次之间除了必要的依赖关系外,自身的特殊逻辑之间基本没有关联,各司其职;输入处理也单独划分出了一个类来实现。


BUG分析

自己的BUG

​ 在三次作业的中测、强测中,我仅在第一次强测出现了一个bug。该bug出现在输入处理的过程中,忘记了对行尾空白符的识别,导致出现该情况时,程序无法正确识别而输出了WRONGFORMAT
​ 该bug的出现是我在设计输入处理的正则表达式过程中出现的缺漏,没有对空白符出现规则所有可能存在的位置进行覆盖。

测试的方法

  • 静态检查:在重要的逻辑部分对代码做静态检查,比如不同类别的因子的求导规则的逻辑,正则表达式匹配的逻辑。
  • 单元测试:在代码编写过程中没写完一小部分独立性较高的方法就对其进行单元测试,保证无误后才进行之后的编写。
  • 综合测试:针对问题的规则,人为制造一定的复杂样例进行测试。对于正则表达式匹配这种极容易出错的地方,进行重点的测试。
  • 回归测试:三次作业,每一次作业的测试用例都向后兼容,记录下前两次的用例用于第三次作业,节省了部分时间。

Applying Creational Pattern

第一次作业

  • 机会:幂函数如-x,x,1这种项可以用工厂方法构建。

  • 重构:在Polynomial类中新增工厂方法getNegX(),getX(),getOne()

第二次作业

  • 机会:幂函数如-x,x,1;三角函数如-sin(x),sin(x),-cos(x),cos(x)这种因子还有其他一些组合可以用工厂方法构建。

  • 重构:在Term类中新增工厂方法getNegX(),getX(),getOne(),getSin(),getNegSin(),getCos(),getNegCos()

第三次作业

  • 机会:幂函数如-x,x,1;三角函数如-sin(x),sin(x),-cos(x),cos(x)这种因子可以用工厂方法构建。运算符节点构建也可以用工厂方法包裹起来。
  • 重构:
    • 新增抽象工厂接口NodeFactory
    • 新增具体工厂类ObjectFactoryOperatorFactory,实现NodeFactory接口。
    • ObjectFactory类中包含getNegX(),getX(),getOne(),getSin(),getNegSin(),getCos(),getNegCos()方法。
    • OperatorFactory类中包含getPlus(),getSubtract(),getMultiply(),getCompound()方法。

结语

​ 面向对象设计是一门深刻的学问,对数据、行为的抽象思维需要在不断的历练中得到提高。期待之后的系列作业。

posted @ 2019-03-27 21:17  匿堕帷幄  阅读(210)  评论(1编辑  收藏  举报