OO第四单元博客作业

本单元作业架构设计

最后一个单元是UML单元,感觉重在对Uml的理解,以代码编写为辅,因此并没有刻意的去进行类之间的架构设计,而是代码尽量写的舒服顺手一些。

第一次作业

主要利用UML元素的id,使用HashMap对各种UML元素进行相应存储,比较简单直观的完成了此次作业:

通过一个idELeMap就可以实现从id到Uml类的自由转化,十分方便。

然后相应的需求只要建立相应HashMap即可。

private HashMap<String, UmlElement> idEleMap = new HashMap<>();
private HashSet<UmlClass> classesSet = new HashSet<>();
private HashSet<String> duplicateClassName = new HashSet<>();
private HashMap<String, UmlClass> nameToclassMap = new HashMap<>();
private HashSet<UmlInterface> interfaceSet = new HashSet<>();
private HashSet<String> opWithparaSet = new HashSet<>();
private HashSet<String> opWithretSet = new HashSet<>();
private HashMap<String, ArrayList<String>> classToOpListMap
        = new HashMap<>();
private HashMap<String, ArrayList<String>> classToassEndListMap
        = new HashMap<>();
private HashMap<String, String> sonTofatherIdMap = new HashMap<>();
private HashMap<String, ArrayList<String>> sonTofatherInterMap =
        new HashMap<>();
private HashMap<String, List<String>> classToselfinterfacesListMap =
        new HashMap<>();
private HashMap<String, List<String>> classToselfattriListMap =
        new HashMap<>();

private HashSet<String> assIdSet = new HashSet<>();

对于各种方法,只要读懂了相应的Uml类的源码,都不难实现。使用HashMap时需要注意nullpointer的问题。我在构造测试方面感觉收到了一定的困难,这也导致我出现了很低级但很严重的BUG,可见面向对象编程是不能将完整的从构架、编写与测试分离的,否则就有严重后果。

第二次作业

本次作业在第一次作业上进行了功能的扩充,因此我新建的MyUmlGeneralInteraction类别继承了上次的UmlGeneralInteraction类,并且将扩充的方法分别写在了MyUmlGeneralInteraction和mlGeneralInteraction两个类中。由于在存储数据过程中多次重复出现了将一个元素按照一定规律加入相应的HashMap中的需求,因此我编写了MyMethod类,在其中实现了各种静态方法,减少代码的重复。

同第一次作业一样,只要读懂了助教大佬写的7000行Uml源码,相应的方法都有很简单的实现方式(装死
为数不多的需要考虑算法问题的就是循环继承和重复实现的check。

针对循环继承和重复实现,我都使用了BFS进行路径搜索,原理都比较简单粗暴:

因为接口不能继承类,因此对于类,其是否处于循环继承中只需要判断这个类是否会继承到自己;对于接口,其是否处于循环继承中只需要判断其对于其他接口的继承是否会继承自己,因此对每个UmlClassorInterface分成类和接口两种情况进行分别判断,就可以实现。利用sonTofather的Map存储id,找出对应的父子关系,再由idEleMap转化成相应的UmlElement类,进行操作。

public void checkForUml008() throws UmlRule008Exception {
    HashSet<UmlClassOrInterface> except = new HashSet<>();
    for (String id : idEleMap.keySet()) {
        boolean hasExcept = false;
        HashSet<String> hashSet = new HashSet<>();
        UmlElement ele = idEleMap.get(id);
        if (ele.getElementType() == ElementType.UML_CLASS) {
            while (id != null) {
                id = sonTofatherIdMap.get(id);
                if (id != null) {
                    if (id.equals(ele.getId())) {
                        hasExcept = true;
                        break;
                    }
                    if (hashSet.contains(id)) {
                        break;
                    }
                    hashSet.add(id);
                }
            }
        } else if (ele.getElementType() == ElementType.UML_INTERFACE) {
            List<String> extendList = new ArrayList<>();
            extendList.add(id);
            int count = 0;
            while (extendList.size() != 0) {
                count++;
                String interfaceId = extendList.remove(0);
                if (interfaceId.equals(ele.getId()) && count != 1) {
                    hasExcept = true;
                    break;
                }
                List<String> tmpList = sonTofatherInterMap.get(interfaceId);
                if (tmpList != null) {
                    for (String tmpid : tmpList) {
                        if (!hashSet.contains(tmpid)) {
                            extendList.add(tmpid);
                        }
                    }
                    hashSet.addAll(tmpList);
                }
            }
        }
        if (hasExcept) {
            except.add((UmlClassOrInterface) ele);
        }
    }
    if (!except.isEmpty()) {
        throw new UmlRule008Exception(except);
    }
}

判断重复实现也是同理,对每个UmlClassorInterface分成类和接口两种情况进行分别判断,利用sonTofather的两个Map,就可以很直观的实现方法。

public void checkForUml009() throws UmlRule009Exception {
    HashSet<UmlClassOrInterface> except = new HashSet<>();
    for (String id : idEleMap.keySet()) {
        boolean hasExcept = false;
        UmlElement ele = idEleMap.get(id);
        if (ele.getElementType() == ElementType.UML_CLASS) {
            List<String> tointer = new ArrayList<>();
            HashSet<String> hashSet = new HashSet<>();
            while (id != null) {
                List<String> tmplist = classToselfinterfacesListMap.get(id);
                if (tmplist != null) {
                    tointer.addAll(tmplist);
                    while (tointer.size() != 0) {
                        String interfaceId = tointer.remove(0);
                        if (hashSet.contains(interfaceId)) {
                            hasExcept = true;
                            break;
                        } else {
                            hashSet.add(interfaceId);
                        }
                        List<String> tmpinter = sonTofatherInterMap.
                                get(interfaceId);
                        if (tmpinter != null) {
                            tointer.addAll(tmpinter);
                        }
                    }
                }
                id = sonTofatherIdMap.get(id);
            }
            if (hasExcept) {
                except.add((UmlClassOrInterface) ele);
            }
        } else if (ele.getElementType() == ElementType.UML_INTERFACE) {
            List<String> extendList = new ArrayList<>();
            HashSet<String> hashSet = new HashSet<>();
            extendList.add(id);
            while (extendList.size() != 0) {
                String interfaceId = extendList.remove(0);
                if (hashSet.contains(interfaceId)) {
                    hasExcept = true;
                    break;
                } else {
                    hashSet.add(interfaceId);
                }
                List<String> tmpList = sonTofatherInterMap.get(interfaceId);
                if (tmpList != null) {
                    extendList.addAll(tmpList);
                }
            }
            if (hasExcept) {
                except.add((UmlClassOrInterface) ele);
            }
        }
    }
    if (!except.isEmpty()) {
        throw new UmlRule009Exception(except);
    }
}

四个单元中架构设计及OO方法理解的演进

表达式

第一次作业的对于简单多项式式的求导,我采用的是面向过程的编程方式,基本上一个类完成了WrongFormat的判断,一个类完成其余大部分的功能,本质上还是函数式的求解。

第二次作业中,意识到了应该将输入的多项式拆分为对象,而wrong format的判断则融合到了对象中去。

第三次作业中,较为完整的理解了面向对象的内涵,将多项式拆分成了不同种类的类,并且通过类之间的相互继承(以及接口的循环继承)较为完善的写出了正确的程序。

电梯

单从架构上来说,并本单元没有变复杂,而是架构之间的通信较难。

第一次作业要求很简单,但是考虑到扩展性的问题还是多建立了几个类。与上个的单元次次重构不同,开始理解面向对象编程可拓展性的意义。

第二次作业在第一次作业的基础上对具体算法进行了改进,架构上基本不变。

第三次作业引入多电梯,因此在架构上作了很大调整,对于线程即对象这个概念有了较好的认识。

JML

本单元中,主要是学习JMl的相关知识,促进了我对面向对象编程的认识,了解了面向对象在工程和学术上的实际应用。

作业中,架构方面主要是学会了如何合理选择容器,同时在保证架构优美的基础上如何写出效率高的程序。

UML

本单元中,主要是学习UML图构建的相关知识,促进了我对于类整体架构的理解。

作业中,架构方面主要是学会了如何合理继承,类之间如何共享方法和数据结构。

四个单元中测试理解与实践的演进

表达式

  • 第一次作业主要使用手动构造数据然后记下来
  • 第二、三次作业手动构造数据然后自动输入输出

电梯

  • 第一次作业进行线程的简单测试
  • 第二次作业成功搭建较为完整的测评机,能够自动的生成测试数据,并且自动输出测试数据
  • 第二次作业成功搭建更为完整的测评机,能够自动的生成测试数据,并且自动输出测试数据,并与其他同学的代码相互对比(对拍)
  • 学会了使用JUnit进行单元测试

JML

  • 在Tle的惨痛教训后,搭建完整的测评机,自动生成测试数据,自动输出测试数据,与其他同学的代码相互对比(对拍),同时能够输出运行时间。

UML

  • 本次作业有很大测试难度,因此第一次作业没有测试,WA声一片,进一步的认识到了测试的重要性
  • 第二次作业,见识到了大佬的测评机,开拓了视野

课程收获

表达式

在第一单元中,从第一次作业的对于简单多项式式的求导,一步步增加功能到较为复杂的表达式的求导,我在架构设计上也经历了很大方面的进步。

从第一次作业的面向过程,函数式的求解,到第三次作业的使用多个类来进行拆分合作,我可以说,如果不采用面向对象的写法,我绝对不可能完成第三次作业。

通过本单元,我依次学会了:

  • 基本的oo语法
  • 字符串分解处理
  • 继承
  • 接口实现
  • 异常的处理

电梯

从电梯调度(磁盘调度)到进程间通信,也与OS中的很多内容相合。

通过本单元,我依次学会了:

  • java线程的实现
  • 电梯(磁盘)调度算法
  • java多线程
  • 线程间通信
  • 听说了神奇的反射操作

JML

本单元中,学习了JMl的相关知识,同时温习了数据结构的图相关知识。本单元对于复杂度要求较高,对复杂度估计也有了较高要求。

通过本单元,我依次学到了:

  • JML理论
  • JML基本语法
  • 复杂度估计
  • 数据结构图算法

UML

本单元中,学习了UML图构建的相关知识。

课程改进建议

首先要感谢课程组的辛勤付出,可以说确实用心了。相比与之前几个学年的OO课程,可以说进步非常大,学生体验已经有大幅的提高。当然体验这个背后还是要感谢我们辛勤的助教,当第四单元进入烤漆后,依然帮助我们写了解析mdj文件的开源库(从UML单元中对源码的阅读就可以看出助教霸霸们工作量有多大。。。)

大家对于OO课程的进步,也都看在眼里。

相信OO课程可以在大家的努力下,能够越办越好。

接下来是三点意见,不多也不少:

  • 上机时间可以再进行调整,并且上机的难度可以拿捏的更好。上机的指导书有些含糊不清,希望以后可以更仔细一点。
  • JML、UML单元还有很多的改进空间,UML单元的指导书可以进一步完善,而JML单元可以更换JML为单纯的Javadoc(反正学会思想即可)或者提供更完整的工具链。(也许是因为我确实学不太懂JML和UML
  • 指导书可以给出更多的样例,既有助于同学们的理解,也能更好地让同学们测试自己的程序。

OO完结撒花~

17375097 张文浩
posted @ 2019-06-21 21:56  garyzhang99  阅读(122)  评论(0编辑  收藏  举报