272
社区成员




BUAA-OO
] 第四单元:UML正向建模总结本单元所实践的正向建模与开发
总结本单元作业的架构设计,并对比分析最终的代码设计和UML模型设计之间的追踪关系
UML 是一种标准化的,可视化的建模语言。他的优势在于给了我们一个可视和清晰的实现框架。
本单元的项目设计的一个显著特征就是涉及大量繁琐的细节(比如每次借书,预约书有很多要求,又如书籍的转移也要满足很多条件…)。在搭建框架时,我们不可能也不应该陷入这些繁琐细节,而是应该给每个方法定义清晰的功能和返回值以解耦复杂度。
同时,UML可以作为编码实现的直接蓝图,后期根据图实现代码的过程会很清晰,不易出错。
更重要的是,在建模的阶段,我们也可以通过审视UML图在早期发现一些设计上的缺陷,避免在编码阶段造成更大的反工甚至重构。
在我实现的图书管理系统中,图书馆是上层;借还处,预约处等图书馆的组成部分是下层。则上层只负责将请求和相关信息分派到下层,而无需关心下层具体实现。下层只需完成特定业务而无需关注其他。这就好比你去图书馆,你去前台说明你要办理什么业务,前台不会关心具体业务细节,只会告诉你去哪里办理以及通知对应办事处你的信息。
在这个过程中,我们就事实上实现了分层和抽象,同时,每层关注的视角也得到了分离。
在这个阶段,我们只需要根据业务需求考虑顶层抽象。即我们大概需要实现哪些类,业务的处理流程大致是怎样的。
很显然,我们需要一个主类(MainClass
)。然后业务是在图书馆实现的,因此我们需要一个图书馆类(Library)来处理业务。进一步的,我们关注到这样两个问题:
谁是系统服务的对象?谁是系统操作的对象?
答案分别是 Person 和 Book 。也就是说,我们应该还需要构建这两个类。
至此,我们似乎仅使用这四个类就可以完成作业了!
// UML 类图正向建模过程:
这个时候我们的UML图仅有如上四个类,和他们的一些简单的属性。例如:person的id,book的id等。
但是,上面的实现显然不符合逐层抽象和视角分离的架构设计原则。
原因也很简单:你很容易感受到在上述实现中,Library 将是一个棘手的问题,本质原因在于它关注了太多东西,方法之间耦合很高!
受到逐层抽象的启发,我们可以考虑新增Reservation(预约处),Circulation(借还处),Machine(自助查询机),Bookshelf(书架)四个类。
此时,业务处理逻辑就变为了Library接受任务,不关心实现,仅分配给它下属的这四个部分。具体的处理将由这四个类负责。
此时我们的设计就已经分出来了两层。上层关注分配,下层关注实现。
// UML 类图正向建模过程:
此时,UML类图有了上述八个类,每个类有他们的一些属性。
例如:一个Library实例应该有唯一的一个reservation,circulation,machine,bookshelf实例
同时,每个类还有一些比较明显的方法。
例如:bookshelf显然应该有addBook和removeBook。Library显然应该有serveBorrow,serveReturn等方法来调用书架处理借书业务,调用借还处处理还书业务。
第三步是考虑每项业务的具体处理,例如bookshelf要处理借书业务,借书之前要检查该不该借。因此我们又可以进一步抽象,serveBorrow方法作为上层,首先调用checkBorrowValid方法检查该不该借出,若不该,输出并结束;若该,调用borrow方法,给person添加书,给bookshelf删除书。
// UML 类图正向建模过程
此时我们的UML图已经有了大部分内容。
每个类下都有一些具体的方法,尽管我们可能还不清楚具体要传入哪些参数(这需要根据具体实现来考虑),但我们清晰地知道每一个方法要做什么,要返回什么。
例如bookshelf类有serveBorrow,checkBorrowValid等方法,分别返回void和boolean...
此时,我们可以对照UML类图检查一下大致的业务逻辑,如果没有明显问题便可以开始实现。
实现结束后,我们需要对照实现来补全一些UML中没有完善的细节。
// UML 类图正向建模过程
这步结束过后,UML类图便已完成
我们在编码实现之前画UML图,其意义绝非是为了让我们在编码之前便清晰地掌握每个实现细节(实际上也不可能)。其意义是让我们在画图的过程中清晰整个业务逻辑,简化冗余设计,从设计框架上解耦复杂度,提高工程可靠性。同时,也使得架构具有好的可拓展性,便于后续增量开发。
另一方面,UML图还需要随着代码演进不断同步更新,否则会失去其作为蓝图的意义。
根据使用大模型辅助正向建模的体验,总结分析如何引导大模型在复杂场景中完成架构设计任务
以实验课上提到的ROSES框架为例:
ROSES框架
ROSES框架在RTF框架的基础上将输入细分为5个核心部分,以确保清晰、有目的的交互。ROSES在明确角色和目标的基础上,更强调场景和解决方案。
- Role:指定大模型担当的角色
- Objective:描述想要实现的目标或想要完成的任务
- Scenario:提供与请求相关的背景信息或上下文
- Expected Solution:描述期望解决方案或结果
- Steps:询问实现问题的具体方法或步骤
ROSES框架首先指明了大模型看待问题的角色(Role),避免给出的回答过于通俗或过于专业。其次提供请求相关的上下文和背景(Scenario)。以上两步提供了有效的信息,为后续有效交流打下铺垫。接下来描述任务(Objective)和期待的解决方法(Expected Solution)。最后询问解决问题的具体步骤(Steps),这里将解决分为一步一步的实现更符合人类的思维,同时也能更好地引导大模型。
总结地说,在使用大模型辅助正向建模完成复杂场景架构设计任务时,首先给大模型提供必要的信息(背景信息,视角信息等),其次要清晰的描述问题的期待的解决方案,最后还可能需要拆解问题,分步提问来获得更好的提问效果。必要的话,还应当不断向大模型指出其实现中有问题的地方和修改方法,进行多次迭代提问。
在实践中,我通过以上方法进行描述并且提供了指导书,要求大模型设计实现框架。在大模型第一版回答中,他预期在Library类中实现borrowed,returned等服务,但这显然会使得代码耦合度高,不符合逐层抽象视角分离的设计原则。于是我进一步向他指出应当建立借还处,预约处等类来分层抽象,大模型在第二版的回答中实现的框架就比较好了。
总结自己在四个单元中架构设计思维的演进
第一单元聚焦于层次化设计思想。在第一单元中,我初步感受到了java语言封装的重要性,在实践中深化了对抽象和模块化的理解。
层次化设计:
第一单元的代码量超过了两千行,是整个课程中最多的一个单元,业务处理涉及多个阶段,因此很能锻炼我们的层次化设计能力。宏观来看,第一单元要求我们将程序分为解析输入,递归下降,计算化简等多个模块,模块之间有清晰的职责划分。
抽象和模块化:
微观上看,第一单元涉及到了大量重复的代码(如自定义函数的替换),这要求我们合理地抽象出一些方法。同时,一些逻辑上相对独立的操作也可以抽象为一个方法,这样可以降低上层方法的耦合度,便于测试。
第二单元聚焦于多线程安全,生产者-消费者模式的应用。在这一单元中,我深刻地体会到了生产者-消费者设计模式的运作模式以及设计要点。同时进一步实践了模块化设计的思想,通过分离各板块职责来降低复杂度。
生产者-消费者设计模式实践:
在这一单元中,我深刻地体会到了生产者-消费者设计模式的运作模式以及设计要点。学会将输入、调度、电梯运行分离为独立线程,通过共享队列实现通信。
进一步体验模块化和层次化:
将系统划分为输入层、调度层和电梯控制层。输入层解析输入,将请求添加至共享队列。调度层从共享队列中获得输入,将输出分发给到电梯线程。电梯线程实现具体业务。这种分层设计使得新增功能时只需修改特定模块,而非全局重构。
第三单元聚焦于规格化设计的实践。在这一单元中,我深刻地体会到了规格与实现分离的思想,感受到了契约式编程的魅力和可靠性。
关注性能:
这一单元加深了我对性能的理解,我直观的体会到了不同数据结构和算法在实际工程应用中的巨大差别,这启发我在架构设计时不仅要考察业务处理逻辑,也要关注实现的时空开销。
功能模块的高内聚设计:
将系统划分为图模型层(维护节点与边)、算法层(实现查询逻辑)、接口层(暴露 JML 方法),各模块通过抽象类和接口解耦。例如,Graph
类封装图逻辑,Network
类管理具体业务,实现模块间低耦合。
第四单元聚焦于UML正向建模的实践。在这一单元中我进一步感受到了先设计再编码的重要性,深刻理解了正向建模,可视化设计,模式复用的核心价值。
需求抽象与模型驱动开发:
通过 UML 类图、状态图和顺序图完成从需求到实现的系统化映射。例如,将图书馆的借还处、预约处、书架等实体抽象为独立类,并通过关联关系(如Library
类聚合各办事处)明确协作逻辑。这种 “先建模后编码” 的流程使架构设计更具前瞻性,避免了边写边改的混乱。
逐层抽象,视角分离:
指将复杂的任务拆分为若干不同的关注点。每个部分只处理特定的问题。这样做的好处是每个模块只用关注一个特定职责,他与其他模块之间的依赖就会减少,逻辑就会更清晰,实现耦合度降低。
总结自己在四个单元中测试思维的演进
在第一单元中,我的对测试的理解还停留在手动构造一些复杂度有限的输入上。这样的测试方法只能测出一些较为明显的问题。
第二单元我尝试了搭建自动化测试,在这个过程中感受到了自动化测试在覆盖率和效率上的巨大优势,但是自动化测试的问题主要在于数据生成的随机性上。于是在第二单元的后两次作业中,我又尝试了设计不同的数据生成策略来构造不同类型的数据。这样的尝试带来了很好的效果。
第三单元进一步拓展了我对测试的系统化认知。在这一单元中,我实践体验了Junit测试,黑箱测试,回归测试等多种测试方法。
第四单元我接触到了交互式测评的概念,在测评机的设计中实践体验了交互式测评。
总结自己的课程收获
OO课程首先给我带来的专业知识上的巨大收获。在这一学期中,我经历了从开学时对java语法还不太熟悉的小白到学期末能自主设计,开发和测试千行级别任务的java入门者的蜕变。
另一方面,面向对象课程中封装和抽象的思想在所有计算机课程中都有重要的实践,对我学习这些课程有一定帮助。另外,这门课程极大的改变了我对测试的认知,从最开始只会手动构造样例到搭建自动化测试,再到根据具体任务选择合适的测试方法,生成不同策略的数据等等。
最后,OO课程还锻炼了我的抗压能力,让我在性格和认识上都变得更加成熟。
当敲下这篇博客的最后一段,才悄然意识到告别已经如期而至
那些熬红的夜,那些难以复现的线程漏洞,那些难忘的,感动的,遗憾的都已永远地镌刻在了昨天
多年以后
你会笑着向别人讲述这个春天的故事
课程终会翻到末页,但那些在代码里生长的隐喻
终将化作探索迷宫时,我们掌心通往永恒的纹路