BUAA-2024 OO-U4总结

李凌-22373240 学生 2024-06-11 23:13:35

写在前面

在面向《对象程序与设计课程》课程(OO)学习中的核心即为面向对象的思考分析方法,这种面向对象的思想在诸多问题的解决中带来了不同思路.在第四单元学习与实践过程中,笔者对于对象选择、封装复用以及高内聚低耦合等诸多思想获得了诸多体会。

本文用于总结OO第四单元的学习时间体会,供未来回顾学习,也为更多面向对象学习者留下少许资料以供参考。

hw_13

1.任务描述

有些意外,整了一个学期活的OO在最后一个单元回归了最经典的图书管理系统,任务内容中规中矩,需要实现一个图书馆系统,管理书本在书架,借还处,预约处和用户四方之间的转移.

当然,任务不可能这么简单,图书管理的代码之外,UML成为了JML的继任者,本轮作业所有类的属性,方法与外部关系都需要使用starUML画进UML类图.

2.设计架构

任务简单,设计便也简单,笔者逐层假设,基本书本类型建立Book类,在此基础,选用map结构进行管理,实现BookMap类对书本进行批量管理,接下来基于BookMap实现四个子类分别实现书架,借还处,预约处和用户.最终上层服务系统实现在Library类中,通过Main类启动.

3.作业后反思

本此作业实现较为顺利,并未出现bug,但在UML的绘制过程中遇到了不少麻烦.

初绘时,任务要求(建议)先画类图确定架构,后写代码,笔者遵循了这条要求.但事实证明,写代码并不是一个能够在一开始就设想好全局细节的工作,最初绘制类图时笔者自认为设计万无一失,但上手动工代码便不断发现缺少方法或数据管理模式不佳,提前设计好的架构反而成了写代码的束缚,最终实际保留到代码中的也只有最基本的类划分.写完代码回看UML,二者不能说毫不相关,只能说关系不大,笔者只能不把原本的类图从零重画.

回顾这一次失败的提前架构的尝试,笔者认为主要问题在于对于思考的细致程度把控不当.动手写代码前先设计架构当然是个好习惯,但这个架构需要细致到什么程度需要考虑.笔者认为可以先设计的是基本类与他们之间的关系是可以提前设置的,再次基础上可以先设计关键数据保存在哪个类中(只确定存在哪,先别定怎么存).类内方法之类也许可以先设计一部分,但按这单元的经验,不上手写是不太可能考虑全面所有需要的方法的,笔者认为干脆先都别动,省得写错修改的麻烦.

hw_14

1.任务描述与设计架构

本次迭代主要是加入了新的图书漂流处,可以接受用户捐入的非正式书本并提供类似书架的借阅功能.此外新添了续借的小功能,还书时检测是否逾期并输出.

作为重头戏的仍然是UML图,这次在类图的基础上增加状态图,要求描述Book的状态在程序中的转移变化过程.

本次代码新增的需求,笔者增加了已实现的BookMap的新子类bookCrossingCenter,在其中实现图书漂流角的基本功能并向Library提供操作接口.增量较少,开发也比较顺利.对于状态图,由于笔者架构中Book作为最底层的基本数据管理单元,直接交互的上层架构仅有BookMap,并无复杂的状态,因此状态图中仅包含:初始化进入实例化状态inBookMap,被移除时进入终态.

2.作业后反思

得益于作业增量开发部分并不复杂,本次作业依然是幸运的未出现bug,这一轮主要出现的问题还是来源于uml,笔者花了不少时间摸索如何使用starUML画好状态转移图,在此做一些记录.

状态转移图,顾名思义,包含两个部分:对象的所有可能状态+对象在这些状态之间转移的时机与条件.

在画图过程中首先应当先定下的就是"状态",状态转移图中状态便是节点,拿本单元的书本为例,可以确定的状态可以是:"在书架上","在借还处"等等.状态的确定要注意两点:应当有意义,一个状态一定是处于一个可以转移到的状态(评测中发现孤立点会报错);应当由条理,梳理一个对象有哪些状态应当是基于它的行为,这个对象是如何创建的?在什么情况下会消亡?会参与到哪些活动中?状态一定是顺着这些活动依次产生,而非单纯的枚举.

确定状态后便是确定转移条件.其实做好前一步后这一步便不会那么复杂,根据画好的节点,我们需要再梳理一遍对象的行为路径,就像走跳格子流程的马里奥,一步步连起转移路径.然后便是补充条件,这里不必多说,填上相关的方法名称和判断条件即可.

hw_15

1.任务描述与设计架构

最后一次任务辣!OO也许在折腾了一学期后也想留下个好印象吧,这一次的迭代格外简单,增量内容耗时可能只有2h上下.内容为建立并维护一套信用积分系统,实现也十分简单,针对每个user设置信用积分属性credit,在会对信用分产生影响的行为中插入信用分增减核查操作即可.

咱们中心已然放在uml上,一次迭代一个新uml图,这次的新任务意外的不陌生,是流程图.一段流程图往往是针对一个行为整体,需要去梳理这个行为中调用了哪些子行为,产生了哪些对象之间的协同运作与通信交流.拿这次任务需要的预约书本流程来说,我们首先由一个用户向Library系统发起请求(调用oreder相关方法),而后系统依据在柜书籍等信息决策是否接受,接受后在以怎样的策略进行预留,预留后如何对接来取的用户.当我们串起流程中涉及到的各种记录、查询行为并联系起相关对象,那便是一个流程图.表现在代码中,则体现为方法的迭代调用关系,反映一段程序运行中调用的方法嵌套关系.


完结撒花之际的一些感想与记录

对第四单元

谈谈uml

整个第四单元中,功能代码其实只是起到一个例子的作用,核心还是围绕这份实例代码学习uml图的基本使用.

在笔者的理解中,uml图服务于合作开发的需求,其意义在于以一种直观又不失严谨的方式展示一段代码的设计功能与运作方式,方便合作开发中的交流沟通.uml图有着多种类型,其实是基于不同的角度来完成描述工作.那这一单元三次迭代中绘制的三类来说:

  1. uml类图最为直白,平列出项目中所有类与其中的属性方法,标注继承,聚合等关联关系,能够最直接的展示项目中的主要代码内容与类架构.这一部分是画起来最为枯燥的一部分,实际像是在做一份自己代码的缩略图,但实际上一旦完整画出类与类之间的联系,便可以十分清晰的看到从顶层抽象类到底层关联的架构全貌,
  2. uml状态转移图则是隐藏了具体的设计细节,依笔者的观点,状态转移图更像是一有限状态机的形式去梳理代码的运行逻辑,这一部分梳理给笔者带来的更深的对所谓"面向对象"的理解.在一个面向对象的程序中,对象就是需要处理的数据的一种管理与抽象,要解决问题实际就是如何去调动这一堆对象去变化,得到我们需要的运算结果.拿图书馆系统为例,书对象的状态转移图其实就对应着一本书在借还预约等操作中的调度流程,反映出程序的核心运行逻辑.
  3. uml流程图则是站在了类图与状态转移图之间,笔者认为他是二者的一个这种表现.一方面,它对应着方法的递归调用关系与运行流程,展现出了具体代码中的类内/之间的关联;另一方面,它又展现出了程序运行的流程与任务的处理思路,保留了一部分类似状态转移图的流式理解.

总结而言,三个类图实际是从三个角度展示代码设计,具有不同的优势与侧重点;同时围绕同一份代码,他们之间也具有关联与一致性.

代码架构演进

本单元的任务本身(图书馆系统)确实没有什么特别值得分析的地方,但uml的加入让笔者在架构设计等方面受到了一定积极影响.

虽然画uml图时笔者也是嫌弃其繁琐麻烦,但现在回顾来看,uml其实扮演了一个督促者的作用.由于uml与设计紧密关联,若是架构设计混乱,对应的uml图也会变得丑陋(例如类图线条混乱交叉,状态转移图触发条件繁琐复杂),这其实算是倒逼着笔者去认真反思了架构问题.例如笔者不希望类图乱成一张"蜘蛛网",所以严格限制了跨层级的交互行为(例如Library与具体实现的bookshelf交互而非抽象类bookMap),在没有画图时,笔者可能为一时方便就会随手写下,后续也很难注意到,但可视化的图引导了笔者去限制那些不太合理的类间关系.也许在不知不觉中,这也成为了笔者这一单元迭代较为舒适丝滑的条件.

对这学期四个单元的回顾

本学期oo课分四个单元,主题从普通单线程程序设计到多线程设计,再慢慢走向多人合作中所需要规范化工具JML,UML.在这四个单元共12此迭代作业中,我对于面向对象程序的架构与测试有了不同的理解.

代码架构

谈到笔者对oo中的代码架构理解的变化,在刚接触面向对象编程时,作为一名搓了一年半Cpp的学生,笔者认为所谓程序就是一个高端的"计算器",只需负责以尽可能高的效率对于输入返回一个正确的结果,写出的代码常常一个函数动辄几百行.但事实上这种程序编写的思路是十分局限的,在面对现实问题时,不会有规范化的stdin给一个程序使用,现实需求复杂,多变,难以预测.面向对象实际上是让我们跳出这种"计算器"的思路,尝试去以"对象"去描述问题并建模,让代码更加的符合直觉,带来更高的开发上限.

在用面向对象的思维处理问题时,我们思考的起点不再是如何拆分输入给出输出,而是去分析:问题中有哪些元素?这些元素分别有什么特点?有哪些行为?我们需要尝试用抽象的"X类"去对应问题中的元素(指数函数,电梯,红包),用"继承""接口"去概括元素之间的相同之处(表达式,书本容器),用"方法"去实现元素的行为(发送邮件,借书).最终,我们的程序实际是问题情景的一个抽象映像,在模拟中获取我们需要的结果.

测试思维

怎么测代码,这是个很难受的问题,毕竟在课程中我们更多的是同时地扮演代码的编写者与测试者.既然代码出自我手,那必然在我的认知中是正确的,那么要怎么跳出自己的思维惯性并发现bug呢?这就需要运用科学的测试思维.

在过去的四个单元中,为了在中测强测以及互测中似得不那么难看,笔者也是被逼着向自己的代码挥刀,尝试了很多的测试方案.

测试需要数据,一份考察点全面又易于分析的数据可欲而不可求.正如前面所说,自己测自己的程序就好比是问自己一件自己不知道的事情,灵感突发想出的几个刁钻情况显然是不够的.笔者目前发现最好的测试方式就是"随机+临界".要想搓出自己都想不到的数据,random是个好东西.首先是随机测试时,不要再去回味那读过百遍的题面,只去看输入要求,然后将但凡合法的数据都试一遍,听起来很傻,但确实很有用(尤其是第三单元!!!!!!力大砖飞!).在随机测完个千把万把条数据后,剩下的基本就只有临界情况,这一部分主要靠手搓,必须蹭到数据限制的边界/int边界/0等等特殊的位置.记过这样的测试,基本WA的问题可以杜绝.

但是WA也许也并没有那么可怕,TLE是一件更麻烦的事情.TLE时很多时候你的程序并不存在错误,问题是"不够好".这就十分的耐人寻味,此时再说测试,还能怎么测呢?这时候,"比较"就是一种变向的测试.尤其是第三单元!!(没错又是第三单元,甲级战犯),一定要多去和室友同学聊一聊,翻一翻前人留下的智慧,和他人的思路去比较是重要的发现TLE问题的"测试"方式.

总结OO

完结撒花,作为一门JAVA入门课,OO在笔者心中大概是对未来工作最有帮助的几门课之一了吧.回顾这一学期的学习过程,OO这门课确实也是做到了难度合理,带来的收获丰富这两点,带我基本熟练了JAVA即其一套开发工具链与面向对象的编程理念,是好课的(赞).

不过也必须承认在一些方面笔者也存在一些质疑,例如那些极其刁钻的强测/互测TLE点真的有意义吗,给分制度好模糊(碎碎念),在这些方面希望OO能越做越好.

总结总结,笔者感谢OO带来的这段学习经验,也将带着在OO学到的东西继续前行,不断在实践中提高.(>~<)

...全文
73 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧