BUAA OO 第四单元总结博客

<center>BUAA OO 第四单元总结博客</center>

李依隆20373457
  • 总结本单元作业架构设计

  • 总结四个单元中架构设计思维和oo方法理解的演进

  • 总结自己在四个单元中测试理解与实践的演进

  • 总结自己的课程收获

  • 立足于自己的体会给课程提三个具体的改进建议

 

本单元架构设计

本单元的代码主要有三部分组成:类图、状态图和顺序图

类图

类图部分代码的主要功能在于分析类图中的元素和元素间的关系。

public class MyClass {
   private UmlClass umlClass;
   private HashMap<String, MyAttribute> attributes = new HashMap<>();
   private HashMap<String, MyOperation> operations = new HashMap<>();
   private int subClassCount;
   private HashMap<String, MyClass> fathers = new HashMap<>();
   private HashMap<String, MyInterface> realizations = new HashMap<>();
   private boolean visited;
  ...
}

在代码中,我通过封装的方式对类图中的各个元素进行管理。通过在包装类中存储元素的父节点和子节点,可以构建类似树的结构,方便进行查询和管理。

例如上面的类元素包装类中,我们保存了类中所有的属性、操作,以及类的父类、实现的接口等。

 

 

 

状态图

状态图的主要作用在于管理一个包含状态、状态间转移、转移条件等元素的图状结构。

同样,我采用包装类的方式,构建了各层级元素之间的组成关系和树状结构。

public class MyStateMachine {
   private UmlStateMachine umlStateMachine;
   private MyRegion myRegion;
  ...
}
public class MyRegion {
   //1.状态数
   //2.是否关键状态
   //3.两个状态间的触发事件
   private UmlRegion umlRegion;
   private HashMap<String, MyState> states = new HashMap<>();
   private MyState beginState;
   private ArrayList<MyTransition> transitions = new ArrayList<>();
...
}

最高层次的元素为状态机,状态集中包含了Region这一元素对状态图中的各种子元素进行管理。

 

 

 

顺序图

顺序图主要表示不同对象的生命周期,以及生命周期中进行的对象间交流。因此,顺序图的层级结构比较简单,主要就是Collaboration下管理着Interaction对象,interaction则进行lifeline、message、endpoints等元素的管理。

 

 

 

 

初始化

本单元通过官方包将输入的 .mdj 文件处理为一个个的元素,并在其中包含了元素间的关系。因此我们需要在分析和查找前,先根据乱序输入的UML图元素生成一个由包装类管理的UML图结构。

为了完整保留UML图元素间的层级关系,可以通过分层对输入的元素进行遍历查找来构建层级结构。在我的实现中,我通过分层查找的方式分别对三种图(类图、顺序图、状态图)的元素按层级从高到低的顺序进行查找、初始化。

但如果需要更好的性能,可以将三种图看作同一级别相并列的三种元素,并为之添加一个更高级的“根节点”,这样在遍历的过程中就可以同时构建三种图的元素。

 

 

 

 

架构设计思维和OO方法理解演进

封装

在一学期的十二次作业中,我体会比较深刻的是面向对象编程中封装的重要性。

从上面提到的重要的包装类,到根据设计需要将基础的元素通过封装的方式组装成在保留原特征的同时在结构上更加明确清晰的新架构,封装的思想在面向对象设计中(更重要的是在我完成每次作业的过程中)起到了至关重要的作用。

封装的作用(我的理解):

  • 为对象提供更加全面的服务(例如int只是一个数据类型,而Integer类就在保留int类型功能的基础上提供了更多更全面的服务,如int与其他类型(如string)的互相转化、与int类型的比较等)。

  • 为对象划分更加明确清晰的结构(例如在第四单元中,通过封装,将每个元素的父节点子节点、树结构的下属元素等装载进封装类中,方便后续的查找和管理)。

  • 降低耦合度(在不同版本的代码迭代中,我们如果对代码按照逻辑结构进行了封装,就可以极大的降低需要修改和重构的代码规模,将修改限制在封装类之内,而保持接口不变,实现黑箱)。

  • 提高复用性(在所有编程语言中都很重要,比如在c语言中对需要多次进行的操作进行封装成函数,可以多次使用,不必多次编写代码)。

 

树、图结构

从第一单元设计中采用递归下降法、构造表达式树结构,到三单元构造社交网络图关系,第四单元构造类似树的层次结构,树、图是我们OO任务中永恒的话题,也是在科研和工作中非常重要的模型和理念。

(树、图结构的应用场景都是相当广的)例如计算网络上的节点级联、权力结构、平衡性、影响力和权威度等,都是在图结构的相关理念的基础上发展来的。

容器选择

在十二次任务中,我对于java容器的选择和设计有了更加深刻的理解。

选择方面,根据任务的需要进行选择,如果追求

设计模式

单例模式

单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。 因为类控制了实例化过程,所以类可以灵活更改实例化过程。

生产者、消费者模型

以第二单元任务为例。将乘客请求看成“资源”,那么生产资源的类InputGetter称为“生产者”,消耗资源的类elevator称为“消费者”。生产者从输入中读入request并将其加入到托盘中,消费者线程则从托盘中取出资源并将之进行处理。这种设计模式实现了读入线程和电梯线程的协作。

工厂模式

我认为工厂模式是封装思想的一个体现。通过创建工厂类,将创建对象的过程封装起来,只提供需要的接口。这样也降低了类之间的耦合度。

线程同步和安全

通过synchronized关键字和wait、notify关键字实现线程间的同步和互斥。

契约式编程

就是函数调用者应该保证传入函数的参数是符合函数的要求,如果不符合函数要求,函数将拒绝继续执行。如果按照契约式编程的思想编写代码,就要求我们写函数时检查函数参数。有时候是简单的判断某个参数不能为空,或者数值不能小于0。如果在项目中全面应用契约式编程,则应该有一个“契约框架”帮我们来做这些事情。

迪米特法则

一个类对自己依赖的类知道的越少越好。无论被依赖的类多么复杂,都应该将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时,才能最小的影响该类。只与直接的朋友通信。类之间只要有耦合关系,就叫朋友关系。耦合分为依赖、关联、聚合、组合等。我们称出现为成员变量、方法参数、方法返回值中的类为直接朋友。局部变量、临时变量则不是直接的朋友。我们要求陌生的类不要作为局部变量出现在类中。

 

测试理解和实践

测试数据构造思路

我主要采用的是黑盒测试、大数据量随机生成数据和人脑构造测试点结合的方式。

人脑构造测试点,有一个比较严重的问题是。如果我们在设计代码的时候没有考虑到某种特殊的情况,那么在构造手动测试的过程中也大概率难以测试到这个盲点。

因此,就需要借助大量的自动生成数据来弥补这个缺失。

自动生成数据的思路

  • 简单版:(以第三单元为例)

def add_message():
   a = random.randint(-MAXN, MAXN)
   b = random.randint(-MAXN, MAXN)
   c = random.randint(0, 1)
   d = random.randint(-MAXN, MAXN)
   if c == 0:
       e = random.randint(-MAXN, MAXN)
   else:
       e = random.randint(-MAXM, MAXM)

   s = 'am {} {} {} {} {}\n'.format(a, b, c, d, e)


def send_message():
   a = random.randint(-MAXN, MAXN)

   s = 'sm {}\n'.format(a)
   std_in.append(s)

这种生成方式有一个问题,就是大多数生成的指令都会被当作exception,所以实际覆盖到的测试情况是比较少的。

所以如果希望测试的效果更好,就需要一些更加完善的体系来进行测试

  • 通过person_pool、relation_pool等实现id的生成和选择通过instrSet统计和判断指令的生成等等。

以person_pool为例,我们将ap指令生成的person的id作为index,将person的其他属性存到person_pool中。

之后,在ar指令中,我们可以一一定的比例从person_pool中随机选取某个person作为关系连接的人。

等等。

  • 通过参数选择的不同模式的评测,每个模式针对不同的测试数据生成比例,有针对性的测试某一个或几个比较薄弱或容易出问题的测试点。但是这个我最后没有实现,因为时间比较紧张。

正确性评测的思路

使用python进行对拍

p.s.:使用评测机一定要慎重、评测的结果也仅供参考……我的第三单元可以说被评测机坑的挺惨的。之前几个单元大部分采用了手动评测,这单元希望能通过评测机的方式提升性能的同时学习一下自动评测的思路和技术。结果就是太过于相信评测结果,导致强测分一次比一次低,太惨了太惨了。要是拿出一部分评测机的时间来有针对性地构造测试数据,效果应该会好很多。

 

课程收获

  • 广义上的编程能力得到了极大提升。

作为进入计算机学院后第一门真正以高级语言和编程思想为主要学习内容的核心专业课,面向对象课程让我投入了很多精力、也推动我学习了很多相关的知识和技能。最重要的是,它培养了我的编程思维、计算机思维、面向对象思维,也让我的技能不仅限于计算机理论本身,而是拓展到了软件设计思想层面。

  • 锻炼了较大规模代码设计和实现能力。

相对于大一学习的两门编程类课程:C语言程序设计和数据结构(更强调编程中具体算法等细节,属于常规视角),面向对象这门课程更强调宏观视角、较大规模的代码设计和实现,还有相应的设计思想。

  • 养成了良好的代码习惯。

经过一学期面向对象作业的洗礼,如果让现在的我再去看大一写的代码,那真是惨不忍睹……虽然在刚开始使用checkstyle的时候觉得不是很适应,但正是这个看起来有点“多此一举”的检查项目,让我在一学期之后明显感觉到了自己代码变得美观了,让人有读下去的欲望了()。

 

三个建议

  • 希望指导书能够更加清晰易读、减少歧义。虽然能感觉到指导书的编写尽量按照形式化进行,但是还是难免有歧义和误导性的内容,希望能够进一步减少,让读者更放心

  • 希望能够专门设置课程,讲解测试的相关思想和技巧。对于规模较大的代码,大家需要更加成熟和高效的debug和测试、优化思路。

  • 希望能够稍微放宽任务的时限、减少任务量,同时增加对于如何将编程和设计思想应用于实践的讲解。让大家不仅知其然,也要知其所以然。



posted on 2022-06-29 14:19  moonlander  阅读(40)  评论(0编辑  收藏  举报