简述
本次lab2实验真的让我学到了很多,也让我切身体会到需求驱动性学习的必要性。下面就以lab2最难的play chess部分为例,给出我的一些心得。
设计过程
经过lab2的ADT设计训练,我认为优先建立UML类图模型是十分有用的,这会大大提高整体设计的速度和准确性。在之前的编程练习中,我总是习惯于先写好几个基本的ADT类,有后续需求时,再往上添加。这种习惯在一些比较简单的设计中确实可行,但是遇到一些更为复杂的设计就不适用了。因为在一开始并未考虑到类之间的种种复杂关系,这可能让后续的更改变得尤其麻烦和痛苦。
所以经过lab2的训练,我决定在今后的编程设计中更多地采用下面的设计过程:
确立UML类图模型--->写好每个类的AF、RI与方法的spec(这一步需要花费很多时间,但是尤为重要)--->写Junit测试用例--->填代码
抽象类的过程
下面根据我在playchess部分的设计总结几点
大部分类直接基于实际情况来抽象即可,例如这里的chess、board、player、action 这些都能根据实际情况很自然地抽象出来。
还有一些类是自己设计的,为了便于和client交互,例如我设计了Game接口与它的2个实现类
基本类设计成immutable的可以给我们避开很多麻烦,因为较复杂的类(例如这里的player)都是基于基本类来设计的,如果基本类是mutable的话,就要考虑复杂类的表示泄露问题,很是麻烦。
确定类的分层
此步骤应该与设计UML类图模型同时进行,以帮助我们搭建一个合理的设计结构
客户端—>API接口—>较复杂的ADT—>底层ADT
原则:能够实现功能的前提下,类之间的关系应该简单清晰,不要交织错杂
上图就是我在lab2中的UML类图模型,因为之前独立设计一个完整ADT系统的经验较少,设计出这样的模型还是花费了很长时间的。
已经尽量使得类与类的层次清晰、类之间关系简洁了。
实现类的功能
设计好UML类图模型后,可能某些类的功能尚不完全,不能实现要求的全部功能,这时要先去为自己的类补充必要的Rep与Method例如:查询双方历史行动纪录操作就是我在这一步骤中加入的
补充完毕之后,就可以往method中填写代码了,当然某些方法的实现可能需要更多的java语法知识,我们可以根据自己的需求来利用搜索引擎去查询相关java知识,先学习一下,再运用到实验中。因为任何一门语言的语法知识都是特别多的,我们没办法熟练掌握所有的技巧,因此需求驱动效率很高。
例如:我为游戏的双方设置了阵营Camp,这是一个枚举类型,而我此前没用过枚举类,就直接利用搜索枚举类用法,进行相关学习。虽然我在实验中的枚举类很简单,但是在很多枚举类用法的博客中将这一java类解释地很详细,这也拓展了知识。
这里是博客园中一篇讲解枚举类用法的博客,你可以点击查看,我觉得讲的还不错
下面就是我在实验中定义的枚举类,很简单,没有加rep
package P3;
public enum Camp {
WHITE,
BLACK
}
然后在Player类中直接设置一个Camp类的Rep即可,用来表示玩家属于黑方还是白方,非常方便,另外,枚举类是immutable的,可以放心使用
public class Player {
private final List<Piece> pieces;
private final Camp camp;
private final String name;
...(省略各种method)
}
调试
我目前在eclipse中调试主要分为2种
这个不用解释了,java语言是静态类型语言,关于编程语言的静态、动态、强类型、弱类型大家可以参考知乎上一篇文章:
这就是关于语言静态、动态、强类型、弱类型的一篇文章,可以点击查看
在做lab2的过程中,我才发现Junit测试可以跟断点结合起来用,之前我一直以为是独立的。。。。
将这2者结合起来用,可以快速定位bug
操作方式:直接在Junit测试用例中,在想加断点的地方加断点,把它当成源代码中的main方法来调试即可
相关工具
lab2中用到的是画UML类图的插件是AmaterasUML
这是如何为eclipse安装AmaterasUML的一篇教程,可以点击查看(注意:如果你的eclipse版本在4.0之后,可以不用安装教程中的GEF插件。我在装eclipse时,直接去官网装的最新版,已经自带GEF插件了)