BUAAOO-Final-Summary
目录
- 总结本单元两次作业的架构设计
- 总结自己在四个单元中架构设计及OO方法理解的演进
- 总结自己在四个单元中测试理解与实践的演进
- 总结自己的课程收获
- 立足于自己的体会给课程提三个具体改进建议
两次架构设计
核心架构
public class UmlTreeNode {
private UmlElement elm;
private ElementType type;
private int id;
private HashSet<UmlTreeNode> sons;
private UmlTreeNode fa;
/* ... */
}
采用一个装饰者模式,装饰原有的数据类型,使得其有更强大的扩展能力。
在UmlTreeNode
下有UmlClassNode,UmlItfNode,UmlIrNode,UmlLifeNOde,UmlOptNode,UmpStaMaNode,UmpStateNode
子类
于是用这种策略,把原有的稀少的,功能不够全面的结构,用新的,具有强扩展能力的类包装起来。
架构设计演进
面向对象是一种编程思想,当我理解后,我在编程学习中迈出非常大一步。
面向对象是将现实问题构建关系,然后抽象成类 ( class ) ,给类定义属性和方法后,再将类实例化成**实例 ( instance ) **,通过访问实例的属性和调用方法来进行使用。
可以说这四个单元分成了OO的两个关键部分:OOA(面向对象系统分析)和OOD(面向对象系统设计)。
-
OOA(面向对象系统分析)主要内容: 研究问题域和用户需求,运用面向对象的观点和原则发现问题域中与系统责任有关对象,以及对象的特征和相互关系。OOA不涉及针对具体实现采取的设计决策和有关细节,独立于具体实现的系统模型。是一个完整确切反映问题域和用户需求的系统模型。OOA的优势:复用、可扩展、可维护性、弹性。
-
OOD(面向对象系统设计):以OOA模型为基础,按照实现的要求进行设计决策,包括全局性的决策和局部细节的设计,与具体的实现条件相关。OOD的步骤:
- 细化重组类→细化和实现类之间的关系
- 明确其可见性→增加属性
- 指定属性的类型和可见性→分配职责
- 定义执行每个职责的方法→对消息驱动的系统
- 明确消息传递的方式→利用设计模式进行局部设计→画出详细的类图和时序图
OOA
在第一个单元,其实我们还没有OOA的概念,还没有做抽象层次的分析,所以第一个单元逐步进行OOA方面的思考,什么样的设计模式,什么样的设计思路,接口和类的设计,模型的选取,如何高质量的重用代码。
在后续的单元,主要是利用OOA的技巧做一些实际的设计,提取出最必要的要素实现,学会在在设计层面展开,在实现层面取舍。
最终在UML单元实现升华,从解析器的角度深入浅出理解OO。
OOD
全局的设计其实有几个作业开始有体验
- 多项式求导——表达式树中类与接口的构造关系
- 多线程电梯——在多线程场景下学习面向对象思维
- 地铁线路安排——逐步细化地铁设计,抽象逻辑固定,需求一致的算法问题
- UML解析器——从UML语言语法和语义层面,重新理解设计的粒度。
面向对象的哲学背景
其实我们可以看到,学会面向对象的高手,都是富有哲思的大佬。早在数千年前,柏拉图、苏格拉底、或者中世纪的哲学家,提出过类似面向对象思维理解问题的方式
把形式(Forms)看作一种抽象表示,它是真实世界的物体/特征的模板(templates/patterns)
- 个体是分享全部的理念呢,还仅仅是分享其一部分呢?无论是哪一种观点,都可以有反驳的理由。如果是前者,那么一个事物就必须同时存在于许多地方;如果是后者,则理念既然是不可分割的,那么一个具有“小”的一部分的事物就要比“绝对的小”更加小,而这是荒谬的。
- 当一个个体分享一个理念的时候,个体和理念就是同样的;所以就必须另有一个既包含这个个体又包含原来的理念的理念。于是就必须再有一个理念包括这个个体和这两个理念,如此类推从至无穷。这样,每一个理念就不止是一个,而会变成为理念的一个无穷系列。(这和亚里士多德关于“第三个人”的论证是同样的。)
- 苏格拉底提示说,理念也许仅仅是思想;但是巴门尼德指出,思想必须是关于某种事物的。
- 由于以上第(2)条所举的理由,所以理念便不能与分享它们的个体相似。
- 如果有任何理念存在的话,它也一定不能被我们所认识,因为我们的知识不是绝对的。
其实很多设计的内涵是富有哲学的,比如UML的语法设计和他的最终表示,怎么把图形关系用JSON类的树风格解析,这其实就是一个理想结构和现实模板生成过程的转换,可以说面向对象课堂是思维与智慧的课堂。
课程的收获总结
初始探索
第一次设计其实我们都遇到到了不少困难,实际上在过程设计中我们把更多的精力花费在模块之间的衔接上,如果一个模块改动,我们就会去想其他的是否会受到影响,这样一路想下去,就乱了,越想越糊涂,面向对象强调“强内聚,弱耦合”事实上过程设计中也提供函数。其实回过头来想,函数也是一个小小的调用模块,也有接口就是传递参数,而对象是把函数集中在类中,提供了一种方法,而调用方法的形式类调用函数,类为我们提供了更多的模块,算是虚拟的模块,我们只有new一个新的实际对象在内存中表现出来,它才产生了个实实在在的东西。回过头来我们在对对象进行各种操作,这样相对来说就不必麻烦我们去调用个函数而费神了,而更绝的是类把变量也塞进来了,这样变量也就成了对象本身的属性,这样我门在过程中的变量赋值和调用函数就变成了对对象的属性的方法的操作,其实都一样,唯一一点区别就是类是虚拟的需要转化成实在的对象才能进行操作,别的都一样,把对象封装在一起提供一些接口,拱我们使用就行了,这样对模块或者说对象的修改不会影响。
熟能生巧
OO设计是充满惊险充满挑战的过程,我在这个过程中体会到了什么是从自然出发,熟能生巧。面向对象的设计思想是从自然界中来的,因为在自然界中,类(Class)和实例(Instance)的概念是很自然的。Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念,而实例(Instance)则是一个个具体的Student,比如,Bart Simpson和Lisa Simpson是两个具体的Student。Java学起来很有趣,通过学习Java可以提高自己的逻辑思维能力。在学习Java期间我们做了一些程序,我们班的同学也都积极准备,完成的还不错!因为Java是一种面向对象的编程语言,刚接触Java的人可能会感觉比较抽象 ,不过没关系不用着急,上课的时候认真听老师讲解,一些概念知识慢慢去理解,课后多做练习,认真完成课下作业,熟能生巧,哪怕是你的记性再好,课后不去强化练习也没用,只有多练了,当你在做项目时你才能很熟练的写出你想要代码。
白盒测试
大量的同学在debug环节是黑盒测试的,即比较其他同学输出和标准输出的正确性,而这样是劳心劳力、费时费资源的一种朴素测试思路,所以需要白盒测试,来弥补难以覆盖的测试环节和情形。我通过单元测试、全路径覆盖的形式保证了:
- 保证模块中所有独立路径至少被执行一次
- 对所有逻辑值都会测试TRUE和FALSE
- 在上下边界及可操作范围内运行所有循环情况
- 检查内部数据结构以确保其有效性
自行实现性能规格完善策略
在第三次作业中,我发现了现有的规格体系的一个缺点:即无法保证描述方法的时空间复杂度,因此,我在此基础上,加入了关于复杂度的描述规格,用于测试我自己的代码。
(目前,我的规格只能测试图的最短路算法和图论其他基本算法。)
我的复杂度规格描述策略如下:
pre-condition: 表示算法中某一些集合,和他们的大小范围。
parameter: 表示参数属于算法中的哪一个集合,和他们的大小范围。
time complexity: 用时间复杂度的标准形式,要求有 online, offline, worst-case几个关键描述。(省略大O记号)
space complexity: 用空间复杂度的标准形式。
这部分的开发过程有很多困难,由于还没有彻底完善,不方便开源(还在做进一步测试)。
引入这个规格的考虑有如下考量:
- 后续重构要考量该接口是否会丧失原有性能、导致各种问题(进程不同步、需求无法满足)。
- 对调用者友好,能不用透视代码,而从性能和功能两个层次考量是否调用该方法、调用的条件是- 什么。
- 对验证有效,工程问题的正确性和效率(开发效率、测试效率)都和基本的性能要求分不开,能提前做好性能的规格设计,在没有遇到性能问题之前大概率无需顾虑。
- 性能规格可以做理论推导、可以通过调用方法和后续方法的性能规格推导该规格的bound,做到防御性设计。
从JML看设计规格
规格是有很多学习意义的。经过这一段时间对JML规格的阅读以及上次上机时自己真正尝试写JML规格,我深深感受到了JML语言的重要性。只有使用JML语言,在进行程序编写,特别是不同人组队完成一个大型程序的编写时,才可以在最大程度上保证不同人完成在代码可以融合在一起,而不会产生各种各样奇妙的bug。在这一单元的学习后,对前置条件,后置条件,副作用,有了比较好的理解,这是一个方法行为的核心,有了这样的规范,程序员间可以在架构层面上进行交流,也就可以在编码前期,架构设计时期进行交流,减少实现时的错误。这是我在这一单元最为印象深刻的,之后使用JML,我会在代码的注释中写明前置条件,后置条件,以及副作用,保持一个良好的习惯。
从UML看面向对象
Visual Modeling(可视化/图形化建模)对于软件开发(尤其拥有大量代码的复杂、大中型系统和产品)非常重要,而利用建模技术有效地进行系统分析与设计,能够有条不紊、从容不迫地应对、解决复杂和棘手的软件设计难题正是编程高手们所擅长的。软件开发本质上是一种思维游戏,程序代码的好坏其实是开发者思维的体现,是开发者理念高低的体现,决定了迭代开发的效率。普通码农与编程高手的主要差别正是在于思维,尤其在抽象思维、空间思维、逻辑思维等方面。拿到一个需求,脑子里一片空白或者乱糟糟的就开始写代码?编程高手如何编程?当然不是。
UML 帮你对软件架构和设计进行抽象、全面、敏捷地分析与思考
UML 建模方法通过多种图形(Diagram)和视图(View)提供了多个层次、多个角度分析、观察软件架构的丰富手段和灵活表现形式,例如著名的“4+1
视图”(Use Case View, Logical/Design View, Process View, Implementation
View, Deployment View)等。基于这样的思考,软件架构的设计才是全方位、系统化和高质量的。
在思考能力上,针对同一个软件设计问题,架构师常常比一般码农想到的更多,更快,也更正确,而且具有预见性。通过建模来进行系统的分析与设计(如针对 OO 软件的 OOAD,即面向对象分析与设计),在大脑中习惯用高层(high level)、抽象的模型,而不是一行行具体、累赘的代码来进行快速、敏捷地思考和决策,是软件架构师的一项基本功。这不是说代码不再重要,而是因为合格的软件架构师对代码细节、语法技巧等已经烂熟于胸,可以更加超脱、宽广的视野思考一些比代码更为重要的设计。
从UML到理清思路
绘图是整理的过程
- 梳理出需求, 形成简单的文档
- 整理出核心流程, 异常流程和状态
- 便于和团队其他人沟通快速上手业务逻辑
三个具体改进建议
建议一:简化UML课程设计难度
最后一个单元的UML课程设计难度较为难,其实可以分成UML设计和代码实现两个部分,即第一个部分:用学习的UML方法先设计好自己的代码框架。第二个部分:用上次写好的框架来编写代码,利用UML的导入和导出,建议用UML自动导出的类来写代码,再重新导入成UML图,观察两部分区别,作为重大评分要求。这样的分段式练习,可以从设计UML和运用UML两个角度思考,非常符合UML的精神。
建议二:开发测试接口
这学期测试中显示的CPU时间与本地的CPU时间有较大差异。希望老师助教能够在平台上开放测试接口,让同学们对于自己生成的数据进行提前检测,看运行时间,提前调整适应,以避免出现本地和最终测试的CPU时间差异过大的问题。测试接口的另一个好处是,减少没有意义的提交,确保自己的策略完善,当然测试接口的,生成器和校验器不应该提供。仅提供stdin
,stdout
,stderr
的上传,下载接口即可。
建议三:实验课与研讨课
实验课和研讨课的安排顺序这学期感觉有一点慌乱,尤其是研讨课的同学,准备时间有点仓促,而实验课的内容上午才学完,又有点没接受,很多小白同学还需要自己复习才行,其实有点难。。