本单元我们学习了UML建模语言,通过实现图书馆管理系统学习了利用UML绘制类图、状态图、流程图,本单元的重点不在于代码实现,而要求我们学会在实现之前进行合理的架构建模,接下来我将对本单元的学习进行总结。
正向建模与开发
正向建模与开发是一种常见的软件开发方法,也被称为自顶向下开发或瀑布模型。包括需求分析,系统结构设计,编码和测试等环节。
具体而言,开发过程分为以下几步:
- 需求分析
设计实现是为用户需求服务的,因此我们在开始任务之前要明确所要实现的功能,这一阶段我们可以适当忽略具体细节,自顶向下地理清完成任务的逻辑。
- 结构设计
我们可以采用UML语言绘制类图、状态图、顺序图等,通过绘制类图我们可以确定不同类之间的关系,而状态图可以让我们更了解关键变量在不同阶段的变化,顺序图则让我们明确类与类之间的通信关系。
- 代码实现
设计好之后我们便可以进行代码实现,在具体实践的过程中不免涉及到很多细节,此时可能需要对之前的设计进行修改。这并不意味着我们之前的工作是无效的,在设计之下完成代码,在实现过程中修改设计,二者相辅相成有助于我们后续完成调试以及迭代开发。
- 测试修改
在完成代码后我们可以利用第三单元学到的测试方法进行测试,找出问题并及时修改。
本单元架构设计
小型图书馆管理系统有两个功能,一是要在内部进行合理管理以服务读者,二是要与其他图书馆进行通信交流。
图书馆内部管理
在我的设计中,图书馆是一个类,它包括了借阅管理员、自助机器、整理管理员等工作人员,也包括A、B、C三类书籍和所属学校的所有学生。
public class Library {
private final String name;
private final HashMap<String, Book> abooks;
private final HashMap<String, Book> bbooks;
private final HashMap<String, Book> cbooks;
private final ReserveLibrarian reserveLibrarian;
private final TidyLibrarian tidyLibrarian;
private final BorrowLibrarian borrowLibrarian;
private final Machine machine;
private final Logistics logistics;
private final ManageOffice manageOffice;
private final HashMap<String, Student> students;
……
}
学生的所有动作都通过与Library类通信完成,而具体的查询、购买等工作由Library与对应的管理员类通信完成。
public boolean handleFirst() {
if (requestType.equals("borrowed")) {
return library.borrowBook(student, type, bookIndex);
} else if (requestType.equals("returned")) {
library.returnBookLibrary(student, type, bookIndex);
} else if (requestType.equals("smeared")) {
student.smearedBookStu(type, bookIndex);
} else if (requestType.equals("lost")) {
String name = student.lostBook(type, bookIndex);
libraries.get(name).lostBook(type, bookIndex);
Output.punish(library.getName(), student.getIndex());
}
return true;
}
图书馆校际交流
第二次作业要求本校图书馆不存在对应副本时查询外校图书馆是否有对应图书,如果符合借阅条件则要进行图书运输。
具体而言,在处理借阅请求时,如果本校图书不存在对应副本,则再当日处理完其他请求后再次处理该请求。
if (!request.handleFirst()) {
detainedRequests.add(request);
}
……
for (LibraryRequest request : detainedRequests) {
request.handleDetained();
}
我们遍历其他所有图书馆,如果存在副本,则将该副本运送到图书馆管理处,当日闭馆后统计所有图书馆运送出去的图书,次日再分发给各图书馆。
for (Library library : libraries.values()) {
HashMap<String, ArrayList<Copy>> out = library.transport();
for (String receive : out.keySet()) {
transport.get(receive).get(library.getName()).addAll(out.get(receive));
}
}
……
for (Library library : libraries.values()) {
if (transport != null) {
HashMap<String, ArrayList<Copy>> temp = new HashMap<>();
for (String name : transport.get(library.getName()).keySet()) {
temp.put(name, new ArrayList<>());
temp.get(name).addAll(transport.get(library.getName()).get(name));
for (Copy copy : transport.get(library.getName()).get(name)) {
Output.receive(copy.getLibrary(), copy.getType(), copy.getIndex(),
library.getName(),
State.transport, State.transport);
}
}
library.receive(temp);
}
}
OO课程总结
设计思维的演进
- 第一单元
第一单元我们进行了表达式解析,这一单元主要掌握的是“面向对象”的思想,即将所有类视作对象,将任务看成对象之间的协作和交互,初步学习了如何降低类之间的耦合,提高代码复用性的一些方法。但这一单元我的实现是“代码主导”的,即在拿到任务后将重心放在如何进行代码实现,并未进行自顶向下的思考和设计。
- 第二单元
第二单元我们要完成电梯的调度管理,设计上要求我们注意如何确保线程安全,死锁的避免与检测等,对多线程的实现机制有了初步了解。
- 第三单元
第三单元我们需要基于规格语言进行程序设计,在阅读和理解JML语言后实现符合规格的类和方法。感受“契约式编程”的魅力——高可靠性、高可复用性、便于测试……
- 第四单元
第四单元我们通过正向建模的思想完成整个任务,先对任务进行整体架构、然后绘制UML图,在此基础上进行代码编写,这样的流程让我在完成任务的过程思路更加清晰,也便于错误分析和调试。
课程收获
本学期花了大量时间完成OO实验,平均每个单元都会遇到一次很艰难的dubug过程,虽然这OO之路走得艰难,但未来遇到更多更难的任务时,只要我回想这学期的努力,我就有信心去面对任何挑战。