面向对象程序设计第四单元&学期总结
一、写在前面
生活可能不像你想象的那么好,但是也不会像你想象的那么糟,有时候可能脆弱的一句话就泪泪满面,有时候,你发现自己咬着牙,已经走过了很长的路。
本学期的OO课程到了终点站,这一路走来看过了很多风景,也有了些许心得体会。本文将从以下几个方面展开:
-
总结第四单元的架构设计
-
回顾架构设计思维及OO方法理解演进
-
回顾测试理解与实践演进
-
总结课程收获
-
对OO课程的一些建议
二、第四单元架构设计
第四单元围绕UML解析展开,第一次任务要求同学们针对类图进行解析,第二次加入了时序图和状态图,第三次任务添加了错误和异常的判断。
第一次作业
第一次作业针对类图进行解析,课程组已经为我们完成了UMLElement的解析,要求我们在此基础上实现查询操作。为了提高查询的效率,我采取的策略是利用树型结构对UMLElement进行组织,主要分为三层:
第一层 | 第二层 | 第三层 |
---|---|---|
class,interface | attribute, operation, generalization, realization | parameter |
在实现时,有以下要点:
1.为了更好地组织信息,我对提供的元素类型进行了自定义封装,设计实现了以下类:
MyClass, MyInterface, MyOperation
。
2.官方提供的elements数组不保证顺序,因此为了构建树型结构,必须按层次进行三次遍历,每次遍历记录相应层次的信息。
3.采用合适的容器将使查询操作实现起来更加容易,例如针对类名重复,我定义了 classNameMap<className, MyClass>
和 dupClassName<ClassName, Boolean>
两个容器,构造树型时进行如下操作:
String name = element.getName();
if (dupClassName.containsKey(name)) {
dupClassName.put(name, true);//重名了
} else {
dupClassName.put(name, false);//第一次出现该name
classNameMap.put(name, myClass);
}
如此判断重名便可如下展开:
if (!classNameMap.containsKey(className)) {
throw new ClassNotFoundException(className);
} else if (dupClassName.get(className)) {
throw new ClassDuplicatedException(className);
}
4.在进行查询时可以采用记忆化搜索的方式,提高查询效率:
public void getInterfaceList(HashSet<String> names) {
if (hasInterfaceList) { //代表该查询已进行过,可直接返回结果
names.addAll(interfaceList);
} else {
for (MyInterface myInterface : interfaces.values()) {
interfaceList.add(myInterface.getUmlInterface().getName());
myInterface.getFatherInterfaces(interfaceList);
}
if (father != null) {
father.getInterfaceList(interfaceList);
}
hasInterfaceList = true;
names.addAll(interfaceList);
}
}
第二次作业
第二次作业加入了时序图和类图,但是整体思路仍然可以沿用第一次作业的思路,新加入的层次如下:
状态图:
第一次 | 第二次 | 第三次 | 第四次 | 第五次 |
---|---|---|---|---|
state_machine | region | state | transition | event |
时序图:
第一次 | 第二次 | 第三次 |
---|---|---|
interaction | lifeline, endpoint | message |
实现难点主要是如何判断一个状态是否为关键状态,本人采用的思路是bfs:
public boolean isKey(String stateName) {
if (!getReachable) {
setGetReachable();
}
if (!reachable) {
//本身不可达
return false;
}
if (isKeyState.containsKey(stateName)) {
//记忆化
return isKeyState.get(stateName);
}
MyState myState = stateNameMap.get(stateName);
Queue<MyState> queue = new LinkedList<>();
HashMap<MyState, Boolean> visit = new HashMap<>();
visit.put(myState, true);
bfs(queue, visit); /////////////BFS实现////////////////
for (MyState state : endState.values()) {
if (visit.getOrDefault(state, false)) {
//有一个可达,就不是keyState
isKeyState.put(stateName, false);
return false;
}
}
isKeyState.put(stateName, true);
return true;
}
第三次作业
第三次作业在前两次的基础上添加了模型的错误及异常检查,如循环继承、重复继承等等,只要之前两次作业的架构合理,完成本作业的功能并不太难。
三次作业的UML图如下:
三、架构设计思维及OO方法理解演进
第一单元——层次
第一单元的主题是层次化设计,关键在于对表达式进行合理的解析,我采用的思路是在训练中用到的递归下降的层次化解析,主要将表达式分解为表达式、项和因子三层。在解析的基础上完成复杂的计算时,我们只需要将其分配到每个对象,让每个对象完成自己负责的简单任务即可。以下是我的整体设计架构:
本单元是我第一次接触OO设计思想,让我充分体会到了合理进行类的设计和封装给程序设计带来的方便性,为我之后深入理解OO打下了较好的基础。
第二单元——交互
第二单元的主题是线程安全设计,关键在于如何在尽可能提高程序效率的同时确保线程的绝对安全,我采用的设计架构是生产者——消费者模型、流水线模型等,在此基础上设计实现了纵向和横向电梯的look策略及换乘策略。为了实现线程安全,我主要采用了 synchronized
锁来控制临界区及临界资源。
通过第二单元的学习,我深刻领会了如何进行对象间的交互与协作,认识到共享数据需要注意的安全问题等等。
第三单元——规格
第三单元的主题是规格化设计,关键在于在理解JML的基础上把握规格背后的抽象本质,这一单元由于已经给出了架构设计,我的主要工作重心放在了对JML规格的抽象理解及实现优化方面。本单元最大的特点就是完全按照JML规格实现虽然可以确保程序的功能正确,但是很容易写出复杂度过高的算法,我们需要充分理解JML表达的本质,抽象出经典问题,例如连通分量数、最小生成树、最短路径等等,再选择合适的算法实现,如并查集、克鲁斯卡尔、迪杰斯特拉等。
经过本单元的学习,我体会到规格设计对于程序设计的安全性的重要性,在课外我还拓展学习了契约式编程的思想,让我更加意识到设计思想的重要性。
第四单元——模型
第四单元的主题是模型化设计,正如上文所总结的,关键在于对模型元素的层次划分及解析,这一单元的架构设计相对自由,可以说是对之前学习成果的一次检验。在本单元的训练中,我独立完成了封装需要的类、对元素合理分层、选择合适的数据结构执行查询操作等任务,强化了自己的架构设计能力。
经过最后一单元的学习,我对OO的理解已经比较深入,我认识到遇到大型工程任务时,可以跳出往常面向过程思想的限制,尝试合理划分对象,组织对象交互,提炼出设计规格和模型示意图,在此基础上再进行实现和优化将会事半功倍。
四、测试理解与实践演进
测试是整个OO课程的一个重要环节,主要分为两部分:数据生成和自动化测试,而数据生成又分为随机数据生成和手动数据生成,我比较擅长的是手动数据构造,心得如下:
-
第一单元主要针对正则表达式的书写漏洞,例如使用正则表达式搜索
1x
并替换为x
。 -
第二单元主要针对线程安全及调度策略不当导致的死循环。
-
第三单元主要针对时间复杂度高的方法构造边界数据。
手动构造数据主要在互测中发挥作用,但是在自测中还是需要大量随机数据和自动化测试来辅助。在这方面,我主要和同学合作,从数据生成到自动化对拍,完成了一套较为完善的自动化测试工具,其中随机数据生成主要应用python,对拍主要利用linux环境下的shell编程知识,我在其中主要负责对拍部分。
五、课程收获
1.从零开始学习掌握了java编程语言
在四次作业的训练中,我已经可以使用java语言完成中小型的项目,对HashMap、List等容器的应用也比较熟练。
2.学习了多线程的知识并进行了实践
第二单元的电梯作业让我充分练习了多线程的编程技巧,对临界资源、临界区、共享、同步等概念有了更深刻的理解。
3.建立了OO设计思想
经过四个单元,分别对应的四个层次的设计思想的学习,我比较深刻地理解了面向对象思想的含义及重要性,并且能够利用其完成一些大型项目。
4.学习了很多有用的设计模式
我在课外时间阅读了《大话设计模式》一书,学习了解了更多设计模式,创建型、结构型和行为型等等,这给予我很多启发。
5.很多课外知识
git的使用技巧、IDEA的使用技巧、checkstyle
的编程习惯等等。
六、改进建议
1.实验课
2.JML单元进一步放宽算法实现的复杂度限制,更加注重对规格安全的测试,同时增加让同学们亲自写JML的环节,在互测环节让同学们相互检查JML书写的正确性,引导同学们对JML进行深入讨论。
3.在课程网站的讨论区开放公共提问区,这应当区别于分享贴,在这里门槛更低,类似于交流论坛,同学们可以以发帖的形式自由提问,其他同学跟帖回复,并且对同学开放删帖功能,方便同学们及时清除无效提问或回复。同时将论坛入口放到更显眼的地方或单独开一个板块,为问题采用合适的算法加权排名,让等待时间长的问题更容易被发现。
七、结语
感谢老师、助教和同学在本学期给予我的无私帮助,总体来说本课程带给我的体验非常不错,最后在课程颁奖时竟意外获得了得意门生奖、狼人奖、杰出性能奖和暖心分享奖,我觉得这既是对我的肯定,同时又鞭策我继续前进,希望未来的学习生活能够将本学期的所学所获应用于实际,我会继续努力前进。