面向对象设计与构造第四单元和课程总结
Ⅰ 第四单元总结
一、建模与开发
- 1.建模与开发的总体过程。在第一次作业中,我认真地先用StarUML基本设计好整体结构再开始编写代码,体会了整个过程,设计了相对完善的结构;但后两次作业
感觉StarUML画画改改太麻烦了偷懒进行了一些设计就直接写代码,之后再补充UML图。不过经过第一次的设计,我还是体会到了建模与开发的整体过程。其实使用建模工具先设计再编码往往也不能全部完美设计好开始编码,在实际实际操作中可能是先进行UML建模,中途发现存在一定问题,对UML整体的结构进行了比较大的修改,(这里也体现了先建模的好处——如果直接写代码可能就不得不重构,而在比较轻量的建模操作下重构的代价就小得多)基本完成框架以后就可以编码,在接触到代码的细节后可能还会遇到一些没有建模时尚未考虑周全的细节问题,比如某一个操作需要更多的参数支持等,这时候再返回对建模进行一些修改。建模和编码是互动的过程。 - 2.良好的建模的优势。首次作业比较良好的设计给后来带来了一些方便之处。比如第一次作业的整体架构泛用性比较好,控制(分发)器-组件的大框架在后两次作业没有更改,已经实现的类中的方法只有少量的修改,贯彻了开闭原则。再比如,开始时设计的Books类也是在构建UML模型时设计出来的,让大量组件能直接调用,实现比较简单;后续再添加和一个漂流角也可以方便地持有和复用。
二、架构设计
第一次作业
- 整体设计 根据要求,构造了书架、借还处、预约处和客户四个位置,同时将预约信息也抽象为一个类Order。并由一个控制器LibraryController统一进行命令的分发和控制,这个控制器尽可能只进行对不同位置的交互,不进行具体的操作。控制器持有书架、预约处和借还处,并分别用哈希表和链表存储客户和预约信息;由于书架、借还处、预约处为图书馆组成部分,故LibraryController与其为聚合关系,而客户(同学)及预约信息与它为组合关系。
- 图书信息设计 考虑到各个对象都持有一系列书籍,并且往往对书籍进行一些增删改查的操作,因此在设计的时候考虑加入了Books这个类,让图书持有者(或位置)将Books作为属性持有,将对书籍的一系列操作封装到这个类里面,让操作更简便,代码复用性更高。
- 功能划分设计 将图书馆相应的功能放在图书馆的位置,例如取书放在预约处,借书、还书放在借还处;借阅权限由于涉及到当前借阅情况,因此直接放在客户处。

第二次作业
- 第二次作业的整体设计沿用了第一次作业的结构,仍包括书架、借还处、预约处、客户和预约信息以及控制类和书籍类。
- 新增的类 新增漂流角类实现图书漂流功能。漂流角通过实现和借还处相似的添加书籍和归还书籍操作,完成图书漂流;图书的借阅次数信息直接存储在借阅处,并在借还处新增图书分类功能的函数,以便直接高效地支持图书的升级功能,图书升级以后就直接加入书架中的正式图书,无需进一步操作。另外新增一个管理图书节约期限的类,使用了单例模式,只需按如下配置即可,能够方便地支持新增和修改。
private DateManager() {
terms.put(LibraryBookId.Type.B, 30);
terms.put(LibraryBookId.Type.C, 60);
terms.put(LibraryBookId.Type.BU, 7);
terms.put(LibraryBookId.Type.CU, 14);
}

- 书籍状态变化 根据书籍的位置划分状态。当图书初始化后加入书架,被捐赠后加入漂流处;书架中的书(B/C)被借阅失败则被放入借还处,而被借阅成功则加入客户处;漂流角的书同理;在开关整理中若处于预约清单则放入借阅处;在借阅处被取走则加入客户处;客户还书则加入借还处;闭关整理时借还处的书放入书架;开关整理时若预约处的书逾期则放入书架。

第三次作业
- 信用分维护 直接在用户内添加信用分,并在相应命令实现处添加信用分维护即可。由于信用分的维护位置比较分散,难以集中实现,因此我没有新增一个信用分管理的类,避免比较奇怪的关联关系。这里有一个需要明显调整的地方,在之前的捐献实现中,并没有记录捐献的用户,因此本次作业中书籍升级导致的用户信用分提升需要另外实现。我的设计是给控制类新增捐献数据记录的辅助类。
- 预约权限调整 由于预约规则变化,在用户中新增了用户预约权限的查询方法,并在其中维护了一些支持性的数据比如当前正在生效的各类预约数量。

追踪关系
- 通过先设计后编码再调整的方式,UML的模型和代码内容实现了一致性。比如类图与程序能互相找到名字相同的类,类图中每个类的属性和方法一致,类图中的继承、实现、关联关系应和代码实现中的关系保持一致。状态图的逻辑关系和代码中实现的关系一致,trigger的方法能在代码中找到对应等。
Ⅱ 课程回顾
一、设计思维
- 逐步调整的设计,这是在本课程中对设计的最大体会。刚开始设计的时候可能遇到设计考虑因素过多导致过分封装和抽象或者设计太少导致后续代码可能重构的问题。一个良好的折衷是先对基本框架进行设计,并预留好进行扩展的可能性,然后再在编码的过程中逐步调整。这在第一单元和第四单元中都充分体现。
- 多线程和共享对象的设计,在多线程单元的学习中重点掌握了利用共享对象进行通信的方法,这种方法不但对多线程程序适用,实际上对一般的程序也有一定的启发意义,即在设计时,如果遇到多个类共同关联的一个数据包,也可以打包成共享对象进行;对于全局数据可以采用单例模式进行实现。
- 规格设计,在第三单元中了解到了基于规格的设计方法,这种方法尽管非常麻烦,但是无二义性,完成规格设计以后编码变得比较容易,同时从交流的角度来说是对程序的功能的严格描述。
- 模型设计,如果说规格是对设计的粒度足够细的说明的话,模型则是对设计的在各种侧重点上足够整体的抽象,比如说类图是对类属性方法和关系的抽象,顺序图是类间交互的抽象。这种抽象方法有利于可视化和从整体上看清系统的设计,从而便于看出设计潜在的问题和进行设计的演示。
二、测试思维
在前三单元中我都用自行构造的程序进行了一定的测试,其中第二单元进行了比较完备的测试,在测试、互测和debug中积累了一定的测试经验。所有代码的验证都采用的是数据生成-答案验证的测试方法,比较遗憾没有进一步了解形式化验证方法。
三、课程收获
- 在本学期的学习中深入了解了面向对象的特性,更了解了不局限于面向对象的代码设计方法和设计模式,比如递归相关的层次化设计及相关的递归控制和克隆问题、支持代码复用的继承/接口设计、使用生产者/消费者模式和共享对象进行的多线程同步互斥方法、死锁的避免、形式化方法、模型的抽象等。
- 提高了代码能力。本学期OO课程应该给我们带来了几千行的代码训练量,在IDE的使用、git的各种操作中提高了编写代码和工具使用的熟练度。
- 熟悉了一些测试方法,可以从前一个部分看出测试思维的演进。
- 最后祝愿OO课程越办越好