BUAA-OO Unit 4 UML

目录

一、正向建模与开发

二、架构设计总结和UML图追踪

1.架构设计总结

2.UML设计时的追踪

(1)图版本一

(2)图版本二

(3)图版本三

三、架构设计思维的演进

四、测试思维的演进

五、课程收获

一、正向建模与开发

        在开始UML这一单元的学习时,我对先进行代码实现还是先进行UML绘图进行了一个深入的思考。首先,我们要画的UML图只是类图而已,其中并不包含任何类之间的具体关系,有的只是如关联、依赖这样比较高层次的概括性强的关系总结。而在面向具体需求,进行代码的具体实现之中,可能遇到的问题是难以预见的。在遇见并解决问题的过程中,我们可能会不断改变类,改变方法等等。若是先进行UML绘图,再进行代码实现,修改时需要同时修改代码和UML,这样比先进行代码实现要低效很多。因此,我决定先进行代码的具体实现,最后根据代码完善相关的UML类图。

        但是,先进行代码实现,这并不意味着我们一上来就是“库库”地敲代码。我选择是先进行代码框架的实现,但是,在这一过程,我也先同步在UML类图中画好了类+类的属性,或者这也许就是课程组的“先UML,后代码”的过程?虽然UML是最先开始的,但是UML它也是最后才完成的,因此我也无法完全领悟课程组的意图。

        在进行设计时,我就已经按照图书馆运行的结构确定好了所有基础类图,当然在之后迭代也会添加新类图,但那也是“锦上添花”,于大框架无关紧要了。所有类图如下所示:

        

        其中的status和CrossingOffice都是后续新增漂流角而相应增加的,其余都是第一次作业最开始就确定好的。细心的朋友可能会发现,其中的QueryMachine似乎比较不常见。因为简单的询问书本操作完全可以在图书馆或者书架BookShelf中用一两个函数就实现了。我想解释的是,这就是先进行架构实现时考虑不到的了,我最开始以为这个询问操作或许会更复杂,比如询问具体某本书,某种书,或者说是书和书之间的关系,这样单独开辟一个询问机器类或许可以更好的实现低耦合的要求,但是后续任务并没有这样新增要求,因此,完成这个单元后看来,这个类就有点多余了。

        以上就是我的进行正向编程中的开始阶段,比较有意义的内容了,后续的迭代过程我将在作业后续架构变化中给出具体解释和分析。

二、架构设计总结和UML图追踪

1.架构设计总结

总的来说我的架构设计其实是比较明了的,这里我贴出最后一次作业的UML类图,并据此分析:

从上图可以看出我的关键类就是Library类,基于这个类,衍生出来了借还处ServeOffice、预约处AppointOffice、查询机器QueryMachine、漂流角CrossingOffice机构执行具体的功能或者交互动作。而Library类则具体负责解析命令,并分发处理命令。如下:

解析命令:

while (true) {
            LibraryCommand command = SCANNER.nextCommand();
            if (command == null) { break; }
            today = command.getDate();
            if (command instanceof LibraryOpenCmd) {
                appointOffice.updateDate(today);
                serveOffice.updateDate(today);
                dailyAppoint = new DailyAppoint(today);
                booksFromServeOffice = new HashMap<>();
                booksFromBookShelf = new HashMap<>();
                todayAcceptedOrders = new ArrayList<>();
                // before open check AppointOffice invalid book
                HashMap<String, HashSet<LibraryBookId>> appointments;
                ArrayList<LibraryMoveInfo> libraryMoveInfos = updateCrossingBooks();
                while ((appointments = appointOffice.hasInvalidBooks(today)) != null) {
                    // check and get when has invalid books in AppointOffice
                    appointOffice.update();
                    // ........
                }
                for (Student student : students.values()) {
                    student.changeCredit(-(student.numOfNewOveredBook(today) * 2));
                }
                PRINTER.move(today, libraryMoveInfos);
                ListIterator<LibraryReqCmd> li = unRespondOrders.listIterator();
                while (li.hasNext()) {
                    LibraryReqCmd unRespondOrder = li.next();
                    dealUnRespondOrder(unRespondOrder, li); }
            } else if (command instanceof LibraryCloseCmd) {
                // after closed : move books from serveOffice to bookshelf
                // AND move books to AppointOffice
                // AND move booksFromServeOffice to AppointOffice
                //.......
            } else if (command instanceof LibraryQcsCmd) { // 信用积分查询
                LibraryQcsCmd req = (LibraryQcsCmd) command;
                if (!students.containsKey(req.getStudentId())) {
                    Student student = new Student(req.getStudentId());
                    students.put(req.getStudentId(), student); }
                PRINTER.info(command,
                        students.get(((LibraryQcsCmd) command).getStudentId()).getCredit());
            } else {
                LibraryReqCmd req = (LibraryReqCmd) command;
                if (!students.containsKey(req.getStudentId())) {
                    Student student = new Student(req.getStudentId());
                    students.put(req.getStudentId(), student); }
                dealRequest(req);
            }
        }
    }

这里其实将开关门也提取成一个函数会好看很多,但是清楚的同学应该了解这样也需要在类图增加函数,为了偷懒不想干活减少负担减少失误的可能,就没有去实现

分发处理命令:

    private void dealRequest(LibraryReqCmd request) {
        if (request.getType() == Type.QUERIED) {
            dealQueried(request);
        } else if (request.getType() == Type.BORROWED) {
            dealBorrowed(request);
        } else if (request.getType() == Type.ORDERED) {
            dealOrdered(request);
        } else if (request.getType() == Type.RETURNED) {
            dealReturned(request);
        } else if (request.getType() == Type.PICKED) {
            dealPicked(request);
        } else if (request.getType() == Type.RENEWED) {
            dealRenewed(request);
        } else if (request.getType() == Type.DONATED) {
            dealDonate(request);
        }
    }

而具体的部门只是实现了相关的交互功能,就拿ServeOffice来说:

import com.oocourse.library3.LibraryBookId;
import com.oocourse.library3.annotation.Trigger;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;

public class ServeOffice {
    private LocalDate today;
    private HashMap<LibraryBookId, Integer> books;
    private HashMap<String, Student> students;

    public ServeOffice(HashMap<String, Student> students) {
        this.students = students;
        books = new HashMap<>();
    }

    public void updateDate(LocalDate date) {
        today = date;
    }

    @Trigger(from = "formal", to = "stay_serve")
    public boolean checkBorrow(LibraryBookId bookId, String studentId) {
        //
    }

    public void decideBorrow(LibraryBookId bookId, String studentId) {
        removeBook(bookId); //let student borrow the book
        students.get(studentId).borrowBook(bookId, today);
    }

    public boolean decideReturn(LibraryBookId bookId, String studentId) {
        //
    }

    public void removeBook(LibraryBookId bookId) {
        //
    }

    public void addBook(LibraryBookId bookId) {
        //
    }

    public boolean hasBook(LibraryBookId bookId) {
        if (books.containsKey(bookId)) {
        //
    }

    public HashMap<LibraryBookId, Integer> getBooks() {
        return books;
    }

    public void clearBooks() {
        this.books.clear();
    }
}

其中实现了加书删书等交互行为,其他的就没有了。

2.UML设计时的追踪

下面是我最开始的UML类图的绘画:

(1)图版本一

可以看到和最终的UML类图相比还是差了挺多内容的,但是基本的框架都已经有了。

接下来进行第一次迭代:

(2)图版本二

可以明显看到,新增了CrossingOffice实现漂流角的相关实现,以及增加了ENUM类Status,用来模拟捐赠图书复杂的状态转变,以及转正操作。同时,Library和Student类都有属性的调整和方法的增加。用来实现迭代新增的要求。

(3)图版本三

这里重复给出迭代两次后的UML类图:

这里同样可以明显看出,变化最大的是Student类,新增了很多属性以及方法。这里也可以相应的看出第二次迭代是聚焦于学生信用的变化的。当然,Library类里相关受信用分影响的部分也是需要调整和改变的。

三、架构设计思维的演进

        实际上在UML设计时的追踪一节就已经解释了些架构演变的内容了。这里就稍微总结一下。就是在最开始就已经设计好了以Library为功能顶层的类,以后的所有实现基于Library提供的交互,实现相应的接口,或者说是机构类即可。这样实际上,之后的架构设计已经没有太大改变了。而这种架构最初的设计也是一开始就想好了,并没有遗漏什么。非要说改进的话,我觉得可以把QueryMachine类换成Library类里的一个方法就行。

四、测试思维的演进

        实际上,关于测试思维我的设想还是比较少的。由于课程组保证了测试时只对基本功能进行测试,而不会对边界情况等等进行测试。因此,这样我们只需要对我们的代码各种功能进行全覆盖模拟就行了,也就是:排列组合。可以借助我们实现的顺序类图,对各种消息传送的先后顺序进行排列组合,这样即可以测试代码,也可以测试顺序图合理性,一举两得!

五、课程收获

        这一单元的收获还是很多的。完整地学习了UML的类图、状态图、顺序图以及相关的知识。学会了如何先从顶层开始设计,之后一步一步进行改进和完善就行了。帮助我们学会了更多地在敲代码前的工作该如何进行更充分的思考。

        而对于这门课程的收获,我在之前的单元总结里也说了很多了。这里说一下总体感受吧。OO这门课还是很好的完成了它该有的作用的。教会了我们很多关于面向对象编程的知识。但是实际上“面向对象”我们在先导课已经感触够“充分”了。正课中更多的则是补充知识,包括但不限于“递归下降解析字词”、“多进程调度处理同步互斥”、“争议很大深受其害的JML”、“简单舒心让人快乐的UML”(快乐部分不包括画图,画图还是挺容易出错的)。这样就组成了我们的OO课程。

        实际上我对于OO的体验是没那么满意的,中测的测试不完善,会把小错误放进强测造成:大分数消失。种种原因导致OO得分并不高。希望我和OO能一起进步吧()

  • 32
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值