OO unit4 单元总结

刘锦涛-23373105 2025-06-10 23:02:44

OO unit4 单元总结

当指针划过凌晨三点的代码编辑器,屏幕上图书馆系统的状态迁移图终于完整闭合 —— 从书架上的书籍被预约,到用户取书时的状态变更,再到逾期未取的自动归还,每一条状态转换线都串联着三天来对架构设计的反复推演。本单元作业以图书馆管理系统为载体,在实现书籍借阅、预约、阅览等核心功能的过程中,我深刻体会到 UML 建模如何从抽象层面指导代码架构的搭建。这种从类图构思到状态图细化,再到顺序图验证的正向开发流程,恰似为复杂系统绘制精准的 "施工蓝图",让代码实现不再是盲目的逻辑堆砌,而是基于模型驱动的工程实践。

本单元所实践的正向建模与开发

正向建模与开发是我从需求分析开始,通过创建 UML(统一建模语言)模型来设计系统结构和行为,然后依据这些模型编写代码的开发方法。在这个图书馆管理系统的开发中,UML 可以帮助我更好地理解需求、设计系统架构以及进行代码实现。下面我将结合提供的代码,详细阐述 UML 在设计过程中的作用。

UML 对设计的帮助

1.类图(Class Diagram)

类图用于展示系统中的类、类的属性和方法,以及类之间的关系。通过类图可以清晰地了解系统的静态结构,为代码实现提供蓝图。

1.类的识别

从代码中可以识别出多个类,如BookHotBookshelfUserReadingRoomBookshelfAppointmentOfficeBorrowAndReturnOfficeRunner 等。每个类都有其特定的职责,例如:

  • Book类:表示图书馆中的书籍,包含书籍的 ID、ISBN、预约时间等属性。
    public class Book {
      private final LibraryBookId libraryBookId;
      private LocalDate appointmentTime;
      private final LibraryBookIsbn libraryBookIsbn;
      // ...
    }
    
  • User类:表示图书馆的用户,包含用户的 ID、信用分数、借阅的书籍等属性。
    public class User {
      private final String studentId;
      private boolean isHasBBook;
      private final HashMap<LibraryBookIsbn, Boolean> isHasCBook;
      private final ArrayList<Book> books = new ArrayList<>();
      private int creditScore = 100;
      private final HashMap<LibraryBookId, LocalDate> borrowDates = new HashMap<>();
      // ...
    }
    
    2. 类之间的关系
    类图可以展示类之间的关系,如关联、聚合、组合等。在代码中,类之间存在多种关系:
  • 关联关系Runner 类与 BookshelfAppointmentOfficeBorrowAndReturnOfficeReadingRoomHotBookshelf 等类之间存在关联关系,Runner 类依赖这些类来完成图书馆管理系统的各种操作。
    public class Runner {
      private final Bookshelf bookshelf;
      private final AppointmentOffice appointmentOffice;
      private final BorrowAndReturnOffice borrowAndReturnOffice;
      private final ReadingRoom readingRoom;
      private final HotBookshelf hotBookshelf;
      // ...
    }
    
  • 聚合关系:Bookshelf 类包含 HotBookshelf 对象,Bookshelf 类与 HotBookshelf 类之间存在聚合关系。
    public class Bookshelf {
      private final HotBookshelf hotBookshelf;
      // ...
    }
    

    2.状态图(State Diagram)

    状态图用于描述对象的状态变化以及状态之间的转换条件。在图书馆管理系统中,书籍和用户都有不同的状态,状态图可以帮助我们更好地管理这些状态。
    书籍的状态
    书籍有多种状态,如在书架上、被借阅、被预约、在阅览室等。代码中通过 LibraryBookState 枚举类型来表示书籍的状态,Runner 类中的 addTrace 方法记录了书籍状态的变化。
    import com.oocourse.library3.LibraryBookState;
    import com.oocourse.library3.LibraryTrace;
    // ...
    public void addTrace(LibraryBookId bookId, LibraryTrace libraryTrace) {
      if (!bookTraces.containsKey(bookId)) {
          ArrayList<LibraryTrace> traces = new ArrayList<>();
          traces.add(libraryTrace);
          bookTraces.put(bookId, traces);
      } else {
          bookTraces.get(bookId).add(libraryTrace);
      }
    }
    
    状态图可以清晰地展示书籍状态之间的转换条件,例如,当用户借书时,书籍的状态从 BOOKSHELF 转换为 USER;当用户还书时,书籍的状态从 USER 转换为 BORROW_RETURN_OFFICE

    3.顺序图(Sequence Diagram)

    顺序图用于展示对象之间的交互顺序,强调消息的传递和时间顺序。在图书馆管理系统中,顺序图可以帮助我们理解系统中各个对象是如何协同工作的。
    预约操作顺序图

涉及的类

  1. Runner:作为系统的核心控制器,接收并处理用户的预约请求。
  2. User:代表图书馆的用户,包含用户的信息和状态,用于判断用户是否具备预约资格。
  3. AppointmentOffice:负责处理预约相关的业务逻辑,如添加预约请求、分配预约书籍等。
  4. Bookshelf:存储图书馆的书籍,提供获取书籍的方法。
  5. HotBookshelf:存储热门书籍,同样提供获取书籍的方法。

顺序图如下

img

本单元作业的架构设计,并对比分析最终的代码设计和UML模型设计之间的追踪关系

1. 图书管理系统架构分析

MainClass 层

  • 职责:作为整个系统的入口,负责从官方指定的 SCANNER 接收各种输入指令,包括图书馆的开门、关门指令,以及用户的借阅、归还、预约等请求指令。
  • 行动:根据输入指令的类型(如 LibraryOpenCmdLibraryCloseCmdLibraryReqCmd 等),将这些指令精准地转发给 Runner 类中对应的执行方法,起到了将外部原始输入转化为对核心业务逻辑调用的桥梁作用。
  • 定位:类似于控制器角色,它不直接参与业务逻辑的处理,而是负责调度和分发任务,确保系统能够根据不同的输入做出相应的响应。

Runner 层(对应设计中的 Library 层)

  • 核心业务操作Runner 类承担了几乎所有核心的业务操作方法,如 handleBorrowed(用户借书)、handleReturned(用户还书)、orderNewBook(用户预约书)、handleOpenCmd(图书馆开门)、handleCloseCmd(图书馆关门)、handelQcsCmd(查询信用分)等。这些方法根据用户的请求和系统的状态,协调各个功能组件完成相应的业务逻辑。
  • 聚合功能组件
    • bookshelfBookshelf 类实例,负责管理馆藏图书,提供图书的获取和归还接口。它可以从书架上查找指定 ISBN 的图书,也可以将图书添加或移除书架。
    • appointmentOfficeAppointmentOffice 类实例,处理预约图书的暂存和“待领取”状态。它接收用户的预约请求,当有可用图书时,将图书分配给预约用户,并管理预约图书的状态。
    • borrowAndReturnOfficeBorrowAndReturnOffice 类实例,作为图书归还后的“临时隔离区”。用户归还的图书先存放在这里,在图书馆关门时,将图书重新放回书架。
    • users:通过 HashMap<String, User> 管理所有学生用户的信息、借阅历史、信用分等。可以根据用户 ID 获取用户对象,对用户的借阅、归还、预约等操作进行管理。
    • readingRoomReadingRoom 类实例,维护阅览室内的图书秩序。它管理在阅览室阅读的图书,确保一人一次只能在阅览室阅读一本书。
  • 开关门操作handleOpenCmdhandleCloseCmd 方法是图书馆运作状态转换的关键节点。开门时,系统会处理预约过期的图书,分配预约图书,将热门图书移动到正确的书架;关门时,系统会将归还的图书放回书架,对未归还的阅读图书进行扣分处理。
  • 输出处理结果:通过课程组提供的 PRINTER 工具,向外界播报处理结果,包括借书、还书、预约等操作的成功或失败信息,以及图书的移动信息等。

功能组件层

  • Bookshelf
    • 数据结构:内部通过 ArrayList<Book> 存储所有图书,提供了按 ISBN 查找图书的方法。同时,通过 HotBookshelf 管理热门图书。
    • 功能:负责图书的存储和管理,提供图书的添加、移除和查找接口。还会根据图书的借阅情况,将热门图书移动到热门书架,非热门图书移动到普通书架。
  • AppointmentOffice
    • 数据结构:通过 ArrayList<LibraryReqCmd> 存储预约请求,HashMap<String, ArrayList<Book>> 存储已分配给用户的预约图书。
    • 功能:接收用户的预约请求,当有可用图书时,将图书分配给预约用户,并管理预约图书的状态。同时,检查预约图书是否过期,将过期的图书放回书架。
  • BorrowAndReturnOffice
    • 数据结构:通过 ArrayList<Book> 存储归还的图书。
    • 功能:作为图书归还后的临时存储空间,在图书馆关门时,将图书重新放回书架。
  • User
    • 数据结构:通过多个 HashMap 管理用户的借阅信息和信用分,如 HashMap<LibraryBookId, LocalDate> 存储借阅日期,int 类型的 creditScore 存储信用分。
    • 功能:管理用户的借阅、归还、预约等操作,根据用户的操作更新信用分。同时,提供检查用户是否可以借阅、预约图书的方法。
  • ReadingRoom
    • 数据结构:通过 ArrayList<Book> 存储在阅览室阅读的图书。
    • 功能:维护阅览室内的图书秩序,确保一人一次只能在阅览室阅读一本书。在图书馆关门时,将图书放回书架,并对未归还的阅读图书进行扣分处理。

数据实体层

  • Book:核心数据对象,存储书籍的核心数据,如图书 ID、ISBN、预约时间等。提供了获取图书信息和设置预约时间的方法。
  • User:存储用户的信息,如学生 ID、信用分、借阅的书籍等。提供了添加、移除图书,检查是否可以借阅、预约图书,计算信用分等方法。

2. 最终代码设计和 UML 模型设计之间的追踪关系

类图追踪

  • 对应关系明确:代码中的类与 UML 类图中的类基本一一对应。例如,Runner 类对应设计中的 Library 类,承担核心业务逻辑的调度和管理;BookshelfAppointmentOfficeBorrowAndReturnOfficeReadingRoom 等类与 UML 模型中的功能组件层的类相对应,负责具体的业务功能实现;BookUser 类对应数据实体层的类,存储核心数据。
  • 属性和方法映射:类图中定义的类的属性和方法在代码中都有相应的实现。例如,Book 类在类图中定义了图书的基本属性,如 ID、ISBN 等,在代码中也有对应的成员变量和访问方法;Runner 类在类图中定义了各种业务操作方法,如借书、还书、预约等,在代码中都有具体的实现逻辑。

顺序图追踪

  • 交互流程一致:顺序图描述了对象之间的交互顺序和消息传递,代码中的业务逻辑实现与顺序图的交互流程一致。例如,在用户预约图书的顺序图中,用户向 Runner 发送预约请求,Runner 检查用户资格后将请求转发给 AppointmentOfficeAppointmentOffice 处理请求并分配图书。在代码中,Runner 类的 orderNewBook 方法实现了用户资格检查和请求转发,AppointmentOffice 类的 addReqgetOrderedBooks 方法实现了请求处理和图书分配。
  • 消息传递准确:顺序图中的消息传递在代码中通过方法调用实现。例如,Runner 类调用 AppointmentOffice 类的方法,AppointmentOffice 类调用 Bookshelf 类的方法,这些方法调用对应了顺序图中的消息传递,确保了系统的交互逻辑正确执行。

状态图追踪

  • 状态转换对应:状态图描述了对象的状态变化和状态转换条件,代码中的业务逻辑实现与状态图的状态转换对应。例如,图书的状态在状态图中定义了在书架上、被借阅、被预约、在阅览室等状态,在代码中通过 LibraryBookState 枚举类型表示图书的状态,Runner 类的 addTrace 方法记录了图书状态的变化,确保了图书状态的正确转换。

3. 最终类图

img

大模型辅助架构设计

在使用大模型辅助正向建模的过程中,我发现引导大模型在复杂场景中完成架构设计任务需要一定的技巧。

首先,要明确清晰地描述问题和需求。在设计图书馆管理系统时,需要详细说明系统的功能需求,如书籍的借阅规则、用户的信用积分计算方式等。只有让大模型充分理解问题的背景和要求,才能得到更符合预期的架构设计。例如,我们需要向大模型说明不同类型书籍的借阅期限不同(如 B 类书籍借阅期限为 30 天,C 类书籍借阅期限为 60 天),以及用户信用积分的增减规则(如按时归还书籍加分、逾期归还扣分等)。

其次,可以通过提供示例和约束条件来引导大模型。在描述需求时,可以给出一些具体的业务场景示例,让大模型更好地理解系统的使用方式。同时,设定一些约束条件,如系统的性能要求、代码的可维护性要求等,帮助大模型生成更合理的架构设计。例如,在设计图书馆管理系统时,可以给出一些具体的借阅、归还场景示例,以及要求系统在处理大量请求时的响应时间不能超过一定阈值等约束条件。

此外,与大模型进行交互和反馈也是非常重要的。在大模型给出初步的架构设计后,要对其进行评估和分析,指出其中存在的问题和不足之处,并向大模型提供反馈。通过多次交互和调整,逐步完善架构设计,使其更加符合实际需求。例如,大模型给出的架构设计可能在某些模块之间的交互逻辑不够清晰,我们可以及时反馈给大模型,让其进行调整和优化。

架构设计思维的演进

经过四个单元的训练,我的架构设计思维经历了从基础的面向过程实现到基于UML建模的系统化架构设计的显著演进。这种演进不仅体现在代码结构的优化上,更反映了我对软件设计方法论的理解和应用能力的提升。

第一单元:表达式解析——面向过程思维的初步应用

初始设计思路

在表达式解析单元,我的设计主要基于面向过程的思维。核心思路是将表达式解析分解为词法分析、语法分析和表达式计算三个主要步骤。我使用了简单的字符串处理和递归下降算法来实现表达式的解析和计算。

设计局限

  • 缺乏模块化:代码结构紧密耦合,各个功能模块之间的边界不清晰,导致代码的可维护性和可扩展性较差。
  • 数据结构设计简单:使用基本的数据结构(如字符串、列表)来存储表达式,没有充分考虑表达式的层次结构和运算优先级。
  • 扩展性不足:当需要支持新的表达式类型或运算时,需要对整个代码进行大规模修改,难以应对需求的变化。

收获与反思

这个单元让我深刻认识到良好的架构设计对于软件系统的重要性。面向过程的设计虽然简单直接,但在处理复杂问题时显得力不从心。我开始意识到需要引入更系统化的设计方法来提高代码的质量和可维护性。

第二单元:多线程电梯——从面向过程到面向对象的过渡

架构升级

在多线程电梯单元,我开始尝试使用面向对象的设计方法。将电梯系统抽象为电梯、乘客和调度器三个核心类,通过类之间的协作来实现系统功能。引入了生产者-消费者模式来处理乘客请求和电梯调度之间的关系,提高了系统的并发处理能力。

设计亮点

  • 面向对象设计:通过抽象出电梯、乘客和调度器等类,将系统功能分解为各个对象的职责,提高了代码的模块化程度。
  • 并发控制:使用线程安全的数据结构和同步机制(如synchronized关键字、wait/notify机制)来处理多线程环境下的共享资源访问问题。
  • 可扩展性:通过设计灵活的调度算法接口,支持不同调度策略的实现和切换,提高了系统的可扩展性。

仍需改进的地方

  • 线程安全问题:在处理多线程并发时,仍然存在一些线程安全隐患,如死锁、竞态条件等问题,需要进一步学习和掌握多线程编程的最佳实践。

第三单元:JML规格——基于契约的设计思维

设计核心

第三单元围绕JML(Java Modeling Language)规格展开,我的设计重点是理解和实现JML规格定义的接口和方法。通过严格遵循JML规格,确保代码的正确性和可靠性。在实现过程中,注重使用合适的数据结构和算法来满足规格要求,同时考虑代码的性能和可维护性。

思维转变

  • 契约式设计:学会了从规格出发,将规格转化为具体的代码实现,建立了"先定义契约,再实现代码"的设计思维。
  • 规格验证:通过JML工具链对代码进行静态检查和运行时验证,提高了代码的质量和可靠性。
  • 模块化设计:按照JML规格的要求,将系统分解为多个模块,每个模块负责特定的功能,提高了代码的可维护性和可测试性。

不足之处

  • 过度依赖规格:在某些情况下,过于关注JML规格的实现,而忽略了代码的整体架构设计和性能优化。
  • 缺乏系统级建模:虽然每个方法都有明确的规格定义,但缺乏对整个系统的架构建模和设计,导致系统的整体结构不够清晰。

第四单元:UML建模——系统化架构设计思维的形成

设计方法论

在第四单元的图书馆管理系统中,我全面采用了UML建模的方法进行架构设计。从需求分析开始,通过类图、顺序图和状态图等UML工具,对系统进行了全面的建模和设计。在实现过程中,严格遵循UML模型的设计,确保代码与设计的一致性。

设计亮点

  • UML驱动开发:使用用例图捕获系统需求,类图设计系统结构,顺序图描述对象交互,状态图管理对象状态,形成了完整的架构设计体系。
  • 分层架构:将系统分为表示层、业务逻辑层和数据访问层,各层之间职责明确,通过接口进行交互,提高了系统的可维护性和可扩展性。
  • 模式应用:在设计过程中,应用了多种设计模式(如单例模式、工厂模式、观察者模式等),解决了系统中的一些共性问题,提高了代码的复用性和可维护性。

显著提升

  • 系统思维:能够从整体上把握系统的架构设计,考虑系统的各个方面(功能需求、性能需求、可维护性等),形成了系统化的架构设计思维。
  • 设计与实现的一致性:通过UML建模,确保了设计与实现的一致性,减少了设计与实现之间的偏差,提高了开发效率和代码质量。
  • 问题分析与解决能力:在架构设计过程中,能够识别和分析潜在的问题,并提出有效的解决方案,如通过优化数据结构提高系统性能,通过合理的类设计降低系统耦合度等。

测试思维的演进

在软件设计与实现能力提升的过程中,我的测试思维与方法经历了从简单到复杂、从零散到系统、从手动到自动化的显著演进。最初采用手工样例测试,通过编写简单测试用例、手动输入并验证结果来进行基础功能验证,但这种方式测试覆盖度低、依赖个人经验且重复测试效率低下,难以发现复杂交互中的问题。随着学习深入,我开始关注边界条件与异常处理测试,运用等价类划分、边界值分析等方法,结合自定义测试框架和断言机制,有效提升了代码的健壮性。

随后进入自动化测试框架应用阶段,引入 JUnit/OKTest 单元测试框架,实现测试用例的参数化与数据驱动,并借助测试覆盖率分析工具量化测试覆盖度,大幅提高了测试效率与覆盖度。同时,我还掌握了基于规格与模型的测试方法,依据 JML 规格驱动测试,利用 OpenJML 等工具验证代码与设计意图的一致性,建立了从需求到测试的完整追溯链。

课程收获

当我按下文档保存键的那一刻,面向对象程序设计的课程之旅已悄然行至尾声。回望四个单元的代码交锋与架构思辨,OO 赠予我的早已超越编程语言的语法边界 —— 这是一场从线性思维到对象建模的认知跃迁,一次用类图与状态图解构复杂系统的思维淬炼,更是一段在代码迭代中触摸软件工程本质的探索之旅。那些深夜调试时 IDE 闪烁的光标、UML 图上反复修改的关联线、测试用例通过时的如释重负,都化作理解软件设计哲学的密钥。

在此,我要向课程组的老师们与助教团队致以诚挚谢意!是你们用精心设计的单元任务搭建起阶梯式的成长路径,让表达式解析的递归下降、多线程电梯的并发控制、JML 规格的形式化验证、UML 建模的正向开发依次成为思维进阶的里程碑。尽管赶作业的日子里常与凌晨的代码编辑器相伴,但当看到图书馆系统的状态迁移图在屏幕上完整闭合时,方知那些为架构设计苦思的时光,早已内化为分析复杂问题的底层能力。

这趟 OO 旅程的终点站并非学习的终结,而是面向对象思维的新起点。当我开始用类的封装性思考模块边界、用状态图推演业务流程、用测试驱动验证设计意图时,便已察觉这门课赋予的不仅是编程技巧,更是用工程化思维拆解世界的认知框架。

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

275

社区成员

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

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