Loading

OO Pre3 Summary

OO2021 Pre3

任务概述

设计一个小型邮件信息系统。邮件信息的子信息包括邮箱的用户名,域名,发送年月日甚至时分秒等,初始时这些信息混杂在同一个字符串中。为了方便收件人有效管理邮件,我们需要将邮件信息中的子信息提取出来,以供分类和查询。

Task1-3考察简单的正则表达式以及容器的基础知识和简单应用。

Task4比较独立,考察了正则表达式的性能问题。

Task5考察对数据的简单封装。

Task6对需求进行了一定的调整,考察前几次是否按照面向对象的方式进行设计。

架构

我的架构设计是随着需求的增加而不断调整完善最终确定的,且笔者认为学习一个架构的演化过程比直接学习最终结果要更有意义,所以下面笔者将先陈述演化过程,然后再对架构做一个分析。

架构演化过程

Task1

Task1要求我们把一行中的多条邮件信息根据分隔符分开输出,这个需求很简单,直接实现即可。

Task2

Task2要求我们把多行邮件信息用正则表达式提取出来(其实还是去掉分隔符),由于读入格式以及处理方式发生了一定的变化,所以我将读入逻辑直接抽象成一个类InputInput类对外提供读入方法,返回一个存储着已经分割好的字符串的容器给调用方。有了Input类,读入的变化只需要修改该类的对应方法即可,主类不需要做变动。

Task3

Task3需要我们把开头提到的邮件的子信息提取出来,并且需要回答一系列关于这些信息的询问。提取信息仍然是使用正则表达式,这里用捕获组比较方便且鲁棒性强。注意到这次读入发生了变化,比起前一个Task,这次还要读入询问操作,所以我又让Input类提供了一个专门读入询问的方法。

由于提取信息的方式也发生了变化,这也需要我们改动Input类,所以我考虑把提取信息的逻辑抽象成另外一个类叫做Parser,它对外提供解析单条邮件信息parseMail()方法以及单条询问指令解析parseQuery()方法,这样的话提取信息的方式发生改变时只需要改动Parser类就好了。

由于询问有很多类型,如果放在主类的main方法中枚举到底是那种询问,是很不优雅的方式,所以我把每种询问都单独抽象成相应的类,它们都继承自Operation父类,父类强迫子类实现work()方法,来让子类们根据自己的情况去执行相应的工作逻辑,最后设计一个操作工厂类OperationFactory用于创建各种具体的操作类,这样主类中只需要和读入类,工厂类以及解析类发送信息就可以了。

Task4

Task4需要我们判断邮件的用户名属于哪个类别,其中类别可以用正则表达式来判定。正则表达式的性能优化可以从本题输入长度不超过100的约束条件入手,从而让正则表达式能够在规定的时限内满足我们的需求。

本需求的添加并没有让架构发生什么实质性的变化,我们只需要再设计一个具体的操作类,继承自Operation类,然后修改一下工厂就可以了。

Task5

Task5要求我们能够通过用户名或者发送信件的时间这两个指标来快速查询邮件系统中的邮件。容易发现,这个需求需要通过两个容器才能完成。为了防止因为编程失误而导致两个容器数据不一致的bug,我们需要把这两个容器做一个封装,封装成一个MailContainer,就像Java其他的容器一样,对外提供插入删除和查询方法,从而隐藏掉内部维护容器数据一致性的细节。增加这个类之后,其他类需要做些许调整,比如Parser类需要返回给调用它的解析邮件方法的类MailContainer类型的参数。总体来说工作量大部分在封装容器上,其他部分变化非常小。

Task6

Task6将邮件的输入格式做了很大的调整,并增加了发送地点信息,其他包含的子信息不变,需求是让我们继续提取相应信息,快速维护某个特定地点发出的邮件的相关信息。有了Task5中设计的容器,我们只需要设计一个新的容器PlaceContainer,其键为地点,值为MailContainer,就可以充分复用前面的成果,工作量仅仅是包装容器以及修改一些参数的类型。

在做本问时笔者出现了重大失误,由于当时急着赶火车,所以笔者想得比较粗糙,在第一个版本直接原地修改了MailContainer,给两个内部容器直接添加了新的键,这种写法不仅没有很好的复用之前的成果,还导致了笔者出现了数据不一致等多种bug,通过大量单元测试甚至设计对拍才找到bug。写完之后心情就是十分后悔,不应该为了赶时间而想得那么粗糙,欲速则不达。还好这只是一个课程作业,不是工作中遇到的项目,不然造成的损失将是非常巨大的。

所以6个Task做下来,笔者最终的架构是这样的(夜晚请调整背景之后查看图片):

架构分析

该架构从Task3开始基本出现雏形,在之后的Task中明显感到基本只需要添加新的模块,原来的模块不受或基本不受影响,可以预见到,只要不出现很奇葩的需求,添加功能还是比较简单的。

笔者有一个疑问是,对于各种不同的操作,设计不同的类并利用多态进行操作和只设计一个类并在类中提供不同的操作方法哪个更好?或者说,如何优雅地去进行各种询问操作?对上面提出的两种方法,笔者倾向于单独设计类,理由是当对现有功能进行修改时,只会修改当前类,由于和其他类的代码在物理上是隔离的,所以绝对不会误触而修改之前已有的功能的代码,也可以隐藏不想让其他开发人员看到的代码,并且,编译时也只需要重新编译这个相对较小的类的文件即可。

当然,上面只是感性的认识,并且是从乐观的角度去看待的问题,更严谨客观的方式是使用代码度量工具进行分析,这一部分内容明天会更新上去等笔者把DesigniteJava重新配好再更新。

posted @ 2021-02-24 22:54  BUAA-Wander  阅读(280)  评论(0编辑  收藏  举报