301
社区成员
发帖
与我相关
我的任务
分享title: 大二下面向对象设计与构造课程总结-4
本单元主要分为两个主要任务,首先是需要学习UML建模语言,学会正向建模与开发的思想,其次我们需要结合上述思想,迭代开发一套具有登记、借阅、查询、图书馆内部整理、预约、图书漂流等功能的小型图书管理系统,并尽量在开发过程中,与前置的UML建模相互配合,保证开发的统一性和严谨性
实际上在该单元一开始的学习中,我是对这种过于注重UML建模的开发思想保有怀疑态度的,其主要原因在于,我已经习惯了较为流式的开发思想方式,认为只需要注重于代码的实现,维持好一个相对合理且有可扩展性的代码架构并不是一件难事,在前三个单元的开发中我也的确是这样做的
但是在本单元实际的开发过程中,我越发感觉到正向建模与开发相结合所产生的作用,先前的开发思想固然没错,但是其缺点在于,我们在一次次的迭代开发中,随着代码架构的不断变化,我们会在不经意间疏于对架构中部分细节的理解和记忆,也会因为开发时长过多,导致"只缘身在此山中"而对代码架构的整体性和其内部的交互缺乏较为客观的认知,这实际上在尤其是以后我们需要面临的团队开发中是后患无穷的,“一猛子”扎进代码虽然一开始会有一定的效率优势,但随着时间的推移,开发者对于代码架构的理解可能会产生偏差,甚至于变成"一团乱麻",这是我们极力需要避免的
而正向建模的开发思想则巧妙地迎合了这一需求,在本单元的开发中,随着每次作业中我都尽可能地完善各类UML图,我发现我对于代码架构的整体性和局部细节的记忆和感知更为准确快速了,而类图的绘制也倒逼着开发者去做出更加合理的架构设计,更加注重于各个类别的明确分工和内部实现,而每次开发之后对图的完善又进一步地加深这种理解,称得上是相辅相成

本单元的代码架构主要是采用以Console类为中控台,由其负责接受系统新发来请求并作为消息收发主题,调度起包括AppointmentOffice、DriftingBook等机构类统一活动以完成需求的结构,其中Console的要求接受与消息发送的结构如下
public static int queryBook(LibraryBookId libraryBookId) {
if (libraryBookId.isFormal()) {
return bookShelf.queryBook(libraryBookId);
} else {
return bookDriftCorner.queryBook(libraryBookId);
}
}
@SendMessage(from = "Student", to = "Console")
@Trigger(from = "OnBs", to = {"Borrowed", "InBro"})
@Trigger(from = "AtBdc", to = {"Borrowed", "InBro"})
public static boolean borrowBook(String studentId, LibraryBookId bookId) {
Book book;
if (bookId.isFormal() && bookShelf.containsBook(bookId) && !bookId.isTypeA()) {
book = bookShelf.getBook(bookId);
} else if (!bookId.isFormal() && bookDriftCorner.containsBook(bookId)
&& !bookId.isTypeAU()) {
book = bookDriftCorner.getBook(bookId);
} else {
return false;
}
Student student = getStudent(studentId);
if (qualifiedForGettingBook(studentId, bookId) && !getStudent(studentId).isDiscredited()) {
book.setDate(endOfDay);
student.borrowBook(book);
book.setOwner(student);
borrowAndReturnOffice.borrowingRegistration(book);
return true;
} else if (book instanceof DriftingBook) {
borrowAndReturnOffice.putDriftingBook((DriftingBook) book);
return false;
} else {
borrowAndReturnOffice.putBook(book);
return false;
}
}
public static boolean orderBook(String studentId, LibraryBookId bookId) {
if (getStudent(studentId).isDiscredited()
|| bookId.getType().equals(LibraryBookId.Type.A)
|| !qualifiedForGettingBook(studentId, bookId)
|| !bookId.isFormal()) {
return false;
} else {
if (bookId.isTypeB() && !getStudent(studentId).hasOrderedBType()) {
getStudent(studentId).orderBType();
appointmentOffice.addNewOrder(bookId, studentId);
return true;
} else if (bookId.isTypeC() && !appointmentOffice.orderedBook(studentId, bookId)) {
appointmentOffice.addNewOrder(bookId, studentId);
return true;
} else {
return false;
}
}
}
@Trigger(from = "InAo", to = "Borrowed")
public static boolean pickBook(String studentId, LibraryBookId bookId) {
if (!qualifiedForGettingBook(studentId, bookId)) {
return false;
}
Book book;
Student student = getStudent(studentId);
if ((book = appointmentOffice.pickBook(bookId, studentId)) != null) {
book.setDate(endOfDay);
student.borrowBook(book);
book.setOwner(student);
student.bOrderExpired();
borrowAndReturnOffice.borrowingRegistration(book);
return true;
} else {
return false;
}
}
@Trigger(from = "Borrowed", to = "InBro")
public static String returnBook(String studentId, LibraryBookId bookId) {
Student student = getStudent(studentId);
Book book = student.returnBook(bookId);
if (book instanceof DriftingBook) {
borrowAndReturnOffice.putDriftingBook((DriftingBook) book);
} else {
borrowAndReturnOffice.putBook(book);
}
borrowAndReturnOffice.returningRegistration(book);
if (book.isOverdue()) {
return "overdue";
} else {
student.increaseCredit(1);
return "not overdue";
}
}
public static boolean renewBook(String studentId, LibraryBookId bookId) {
if (getStudent(studentId).isDiscredited()
|| !bookId.isFormal() || getStudent(studentId).notBorrowedBook(bookId)) {
return false;
}
if (!bookShelf.containsBook(bookId) && appointmentOffice.containsBook(bookId)) {
return false;
}
Book book = getStudent(studentId).getBook(bookId);
if (!book.qualifiedToRenew(endOfDay)) {
return false;
} else {
book.renew();
return true;
}
}
@Trigger(from = "InitState", to = "AtBdc")
public static boolean donateBook(String studentId, LibraryBookId bookId) {
DriftingBook driftingBook = new DriftingBook(bookId, getStudent(studentId));
getStudent(studentId).increaseCredit(2);
bookDriftCorner.donateBook(driftingBook);
return true;
}
public static int getStudentCredit(String studentId) {
if (notContainsStudent(studentId)) {
return 10;
}
return getStudent(studentId).getCredit();
}
public static void dealWithCommand(LibraryCommand command) {
LocalDate date = command.getDate();
if (command instanceof LibraryOpenCmd) {
LibrarySystem.PRINTER.move(date, Console.dailyMovement(date, "OPEN"));
borrowAndReturnOffice.dailyCheck(date);
} else if (command instanceof LibraryCloseCmd) {
LibrarySystem.PRINTER.move(date, Console.dailyMovement(date, "CLOSE"));
borrowAndReturnOffice.dailyCheck(date);
} else if (command instanceof LibraryQcsCmd) {
String studentId = ((LibraryQcsCmd) command).getStudentId();
LibrarySystem.PRINTER.info(date, studentId, getStudentCredit(studentId));
} else {
LibraryReqCmd req = (LibraryReqCmd) command;
LibraryRequest request = req.getRequest();
LibraryBookId bookId = request.getBookId();
String studentId = request.getStudentId();
if (Console.notContainsStudent(studentId)) {
Console.addStudent(studentId);
}
boolean mark;
if (request.getType().equals(LibraryRequest.Type.QUERIED)) {
LibrarySystem.PRINTER.info(date, bookId, Console.queryBook(bookId));
} else if (request.getType().equals(LibraryRequest.Type.BORROWED)) {
mark = Console.borrowBook(studentId, bookId);
requestReply(mark, command);
} else if (request.getType().equals(LibraryRequest.Type.ORDERED)) {
mark = Console.orderBook(studentId, bookId);
requestReply(mark, command);
} else if (request.getType().equals(LibraryRequest.Type.PICKED)) {
mark = Console.pickBook(studentId, bookId);
requestReply(mark, command);
} else if (request.getType().equals(LibraryRequest.Type.RETURNED)) {
LibrarySystem.PRINTER.accept(command, returnBook(studentId, bookId));
} else if (request.getType().equals(LibraryRequest.Type.RENEWED)) {
mark = Console.renewBook(studentId, bookId);
requestReply(mark, command);
} else if (request.getType().equals(LibraryRequest.Type.DONATED)) {
mark = Console.donateBook(studentId, bookId);
requestReply(mark, command);
}
}
}
采取了较为明确的分工收发策略,既保证了架构的明确无二义性,又将各个功能的维持权利移交给了各个机构类,体现了高内聚低耦合的开发特性
第一单元的主要任务实现一个具有解析表达式与计算化简能力的解析器,聚焦于对梯度下降法的学习和理解,但随着开发过程的推移,我愈发注意到对代码整体架构的合理设计的重要性,其中表现最明显的便是最后求导功能的实现,在第二次的作业实现中我即时调整了代码架构中至关重要的Term类与Expr类的交互,去除了冗余的代码内容,使得第三次作业的求导功能实现起来十分简易
第二单元的主要任务是实现多电梯调度系统,学习的主要难点在于多线程调度和线程安全的保证,在这一单元架构的设计反而显得不那么考究,主要的难点在于开发者需要根据题干给出的需求,选择最合适的调度算法,并在双桥厢电梯配合的情况下,保证不同电梯间的同步关系,避免死锁和时间空间资源的浪
第三单元主要学习了JML多种条件的意义解读,其主要任务是一种类似于完型填空的算法填写,较为考验编程的基本功和对于JML的解读准确度,在该单元的设计过程中,我们更需要注重对细节的把控,否则可能会在强测中遭遇一些难以感知的不测
在第四单元中,我们充分学习了正向建模与开发相结合的思想,通过将UML与代码架构的增量化开发的结合,我们可以更加严谨地把控好各个结构类的内部实现和交互细节,一定程度上避免了严重的思维漏洞的产生,而在设计时,我也能以已构建好的类图为蓝本,进一步的保证架构的设计的合理性,并以此为标准来指导后续的迭代开发
严格来说对于数据的测试思维并没有发生过大的变化,在调试代码的时候,我们从始至终都需要秉承先基础后性能的思想,即先保证基础功能的实现而后对极端情况和软件性能来进行更加充分的设计,而性能的测算其主要就是在于要学会计算算法的时间复杂度,并尽可能地使用更为优的数据结构,在一些特定情况,我们需要做好时间和空间的权衡,尤其是普通架构下无法保证高效的内容,我们需要加入冗余的数据结构来保证其高效
发自内心地说,面向对象编程这门课(包括先导课),是我在大学生涯的降转前后三年里学起来最有意思也收益最大的一门课程,在两个学期的学习中,基于java的面向对象程序设计思想可以说是深入人心,五次从无到有的小项目的架构设计以及调试的经历,不仅从一定程度上复习了算法基础,也使我系统性地学习到了代码架构合理的构造思路,可以说是收益匪浅,最后我想感谢所有的教师和助教团队的辛勤付出,谢谢你们奉献了一门如此使人满意的课程,祝生活愉快、家庭和睦