面向对象第四单元总结

面向对象第四单元总结

一、第四单元架构设计

首先贴出本单元设计的部分类图

blog4.drawio

本单元的架构设计可以划分为三部分:对原生的UmlElement的改造、初始化与合法性检查、功能实现。

1.对原生的UmlElement的改造

首先介绍对原生UmlElement的改造。由于我们的任务是实现解析mdj文件的相关逻辑,所以助教们已经帮我们完成了从读入到解析的这个过程,并且解析好的数据用定义的UmlElement'数组来存储。但是由于我们在实现相应功能的时候希望能够在类中自定义一些方法来简化,所以必须改造UmlElement。

我将新建的类全部以My为开头命名,来和Uml的类区别。这些新设计的类都继承了Node这个基类。Node的作用类似于UmlElement,它把一些UML元素的共性问题提取出来,例如id, parent_id, name三个字段。此外,我在Node中用HashMap实现了UML元素的连接。

public class Node {
   private final String id;
   private final String name;
   private final String parentId;
   private final HashMap<String, MyClass> subClasses = new HashMap<>();
   private final HashMap<String, MyClass> faClasses = new HashMap<>();
   private final HashMap<String, MyOperation> operations = new HashMap<>();
   private final HashMap<String, MyAttribute> attributes = new HashMap<>();
   private final HashMap<String, MyParameter> parameters = new HashMap<>();
   private final HashMap<String, MyInterface> subInterfaces = new HashMap<>();
   private final HashMap<String, MyInterface> faInterfaces = new HashMap<>();
   private final HashMap<String, MyState> states = new HashMap<>();
   private final HashMap<String, MyStateMachine> stateMachines = new HashMap<>();
   private final HashMap<String, MyRegion> regions = new HashMap<>();
   private final HashMap<String, MyTransition> transitions = new HashMap<>();
   private final HashMap<String, MyInteraction> interactions = new HashMap<>();
   private final HashMap<String, MyLifeline> lifelines = new HashMap<>();
   private final HashMap<String, MyMessage> messages = new HashMap<>();
   private final HashMap<String, MyEvent> events = new HashMap<>();
   private final HashMap<String, MyEndpoint> endpoints = new HashMap<>();
}

2.初始化与合法性检查

第二部分是初始化和合法性检查,这部分由两个类来实现,Initial和Graph。

Initial用来处理UML元素之间的关系。对于UmlGeneralization,UmlInterfaceRealization等,我并没有对其进行改造,而是直接把它们抽象成一种关系。这种关系具体由上述的Node类中的HashMap实现。

public Initial(Node root, UmlElement[] elements) {
       this.root = root;
       this.elements = elements;
       relationInit();
       parameterInit();
       operationInit();
       attributeInit();
       stateInit();
       collaborationInit();
}    

由于第三次作业中的合法性检查对于UML元素之间的关系有密切的关系(循环继承、直接继承等等),所以我把合法性检查放在Initial类中实现。为了更好地实现一些图算法,我把UML元素关系进一步抽象成图,用类Graph来处理。Graph支持增加边和一些图上查询操作。

public class Graph {
   private final HashMap<String, ArrayList<String>> table = new HashMap<>();

   public void add(String src, String dst);

   public boolean onCycle(String src, String o, HashSet<String> visited);

   public boolean notTreeRoot(String src, HashSet<String> visited);
}

3.功能实现

第一次作业和第二次作业的需求是mdj文件解析器的主要功能,我在MyImplementation里实现了这些功能。同时,MyImplementation也需要调用Initial来完成初始化和合法性检查。

二、架构设计思维及OO方法理解

第一单元

第一单元是面向对象程序设计的第一关,作业的目的是为了让同学们初步掌握面向对象设计的思想,体验面向对象的方法论的具体实践。这一单元的架构设计最重要的就是抛弃以往面向过程的设计思路,把我们的程序当作一个虚拟的世界,而不是由函数和逻辑线性排列组成的需求。具体来说,如何把线性的表达式计算问题抽象成多个对象的交互。有的同学建立表达式树,有的同学用递归下降,其实殊途同归,都是在原问题的基础上建立起的更高层次的抽象。

第二单元

第二单元是声名在外的电梯月,这一单元最主要的是掌握面向对象思想在多线程设计方向的实现。在这一单元,我们接触了很多设计模式。从最基础的消费者生产者模式、单例模式,到后面的流水线模式,开阔了眼界。多线程编程的难度比单线程难上许多,从基本的设计模式入手,能够更快掌握编程技巧,使得后面的作业得心应手。记得一位老师曾说过:“设计模式不是用来设计架构的,而是一些具体问题的精妙解法。”在我看来,架构设计和设计模式,更像是“道”与“术”的关系,只有道术相济才能写好代码。

第三单元

第三单元的重点是学习JML,掌握在实际的工作环境中如何使用JML。这一单元单就功能性而言没什么架构可言,因为我们是根据JML实现函数功能,所以整体的设计理念是被定死的,基本没什么设计空间。但是这一单元的内容涉及到了很多图论算法,这就到了考验同学们面向对象功底的时候了。如何对这些图算法进行封装才能够既简洁又高效是我们要考虑的问题。在这一单元我的算法实现的比较混乱,由于我的图是依靠给MyPerson、MyNetwork等原有类添加属性来实现的,就无法遵循开闭原则,维护起来比较混乱。在第四单元作业中,我发现可以把图单独抽象成一个类,只提供增加边和查询信息的功能,完美达成了开闭原则,实现也很简单。

第四单元

第四单元的重点是掌握UML的类图、顺序图和状态图,我们的作业是实现一个mdj解析器。具体的架构设计在第一部分已经详细介绍了,不再赘述。

经过了四个单元的训练,我最大的提高是抽象能力,从需求中抽象出面向对象式的结构的能力。这种能力是理论给不了的,在实战的一次次拼杀中领悟出来的。

三、测试理解与实践

在四个单元的学习中,我搭建过评测机,也构造过一些数据。

评测机最基本的功能是自动让多个程序运行同一组数据,再对比它们的结果是否完全相同。在此之上还可以添加一些新功能。如果使用Linux系统搭建评测机,就可以使用内置的time命令查询系统时间、用户时间和真实时间,这在第二单元中很有用。同样在第二单元中很有用的功能是多线程评测。思路是用python脚本的线程库实现评测机,对于同一份数据,每个线程运行一个jar包,主线程等待所有子线程join后,记录运行结果,装载下一个数据,再唤醒子线程,进行下一轮评测。这很适合第二单元这种耗时长、CPU占用低的程序。

我构造的数据比较少,基本上都是手动构造的。依据的也是自己认为一些容易犯错的地方。还有就是第三单元由于顺便考察了图论算法,所以可以卡时间复杂度和递归栈的深度。

四、课程收获

一学期转瞬即逝,OO也要落下帷幕了,四个单元在眼前如走马灯般闪过。还记得递归下降总是出Bug吗?还记得电梯里的人总是莫名失踪吗?还记得四五十行JML怎么也读不懂吗?还记得重构了一遍又一遍吗?还记得想到新点子时的拍案叫绝吗?还记得那次强测的千古遗恨吗?OO的回忆,真的很多呀。

开学时,你对面向对象很感兴趣,立志要掌握它,你学完了Java的语法,摩拳擦掌、跃跃欲试,正是“昨夜西风凋碧树,独上高楼,望断天涯路”。之后随着课程越来越难,身边的人纷纷望而却步,你却义无反顾地把时间投入到重构和debug之中。你搭评测机、改进算法、追求极致,别人说你是卷王,你却享受在山巅起舞的快感,正是“衣带渐宽终不悔,为伊消得人憔悴”。多年以后,强测的得失与午夜的咖啡都随时间消逝,你在一次项目中忽然来了 灵感,提出的架构让同事们赞叹不已。谈及灵感的来源,你微微一笑,又回想起自己的学生时代,正是“众里寻他千百度,蓦然回首,那人却在灯火阑珊处”。

结束了,故事才刚刚开始。有什么收获吗?又能再奢求怎样的收获呢?

五、改进意见

关于第一单元理论与实践的先后问题

我认为第一单元作为引导我们学习面向对象程序设计的单元,其在内容上设计的很不错,复杂的表达式化简是很适合面向对象的程序范式的。但是我认为理论课和实验课的配合并不是十分完美。我记得我们的理论课是在第一次作业完成之后才开始具体给出一些面向对象的设计建议,比如如何设计表达式树。这导致一些同学在第二次作业的时候陷入了重构还是继续维护原来架构的困扰。我认为老师的本意是希望同学们能够多探索其他的方法,但是在第一单元,同学们还没有掌握面向对象的思想,很可能第一次作业会走弯路。我认为不妨让理论领先于实践,让同学们先学习面向对象的一些实践方法论。

关于微信群问答改善的建议

微信中同学的提问可能被其他消息冲走,或者助教平时并不习惯经常看群,导致助教看不到微信提问。解决方案:可以让负责每个单元的助教单独建群,想要提问的学生自己进群提问,直接@助教。

在提问高发期或者水群高发期,微信中助教对同学的回答很容易被冲走,同学的问题也可能跟助教的回答匹配不上,导致一个问题重复问好多遍。解决方案:助教可以定期(例如每日)把一段时间内解答的问题整理成一个文件,发到群里,并在有人问同一个问题的时候提醒对方看文件。

关于第三单元的建议

第三单元我们专注于根据JML来实现特定的功能,但是没有在作业中考察同学们撰写JML的能力。而且我们的实验涉及到很多图论算法,诚然,这对于我们的编码能力、抽象能力有帮助,但是与JML关系不大。我认为不妨增加书写JML的题目,甚至可以小组作业,一些同学撰写JML,一些同学根据JML写代码。简而言之,增加更贴近于工业界实际使用的训练。当然,这对现有的评分制度和评测机都是挑战。

posted @ 2022-06-28 17:07  hua-0x522  阅读(47)  评论(1编辑  收藏  举报