武器进化与OO 教学重点

前置课程

前置课程: 猜数字,POS机V2的OO版

总览

第一问到第三问刚刚开始要求教练必须坐在旁边,观察TDD的意识是否建立起来了。帮助减少使用鼠标,转而使用快捷键。能在前两问教一些快捷键最好,省的第三问教的太多消化不了。 教学方式: 前三问:1对1pair教学, 第四~五问: 定期Code review

第一问

  1. 这一问的设计主要是纠正学生级学员没有TDD意识而设计出来的。大部分的学生都会习惯性的扎回到先写实现中去。这个题目一定要亲眼看着学院写出第一个Case
  2. 讲解TDD的基本流程。
  3. 除此之外,这一问主要关注,我们要从测试覆盖率的角度看待测试,所有路径都应该被覆盖到,那么具体到这个题目就是:至少有两个case 张三被打败和李四被打败,
  4. 有可能会有其他情况出现,比如随意改变集合,函数的输入不仅仅是参数,return太多,代码太长等问题也请一并处理,具体可以参考

第二问

  1. 如何测试完整的循环结果,如果用了consloe.log就练mock,没用就简单处理,坑在下一问。这一问也要亲眼看着学员写出第一个case
  2. 这一问还是TDD的意识训练

第三问

这一问练习的比较多,分为手艺部分和设计部分

手艺部分要学会使用快捷键,live template和宏,要求在第三问结束的时候,开始设计之前,删掉所有的代码用live template和macro重写一遍(思考工作中的重复)。 训练到的内容细节如下:

要训练出的快捷键有:

切换tab: ctrl+ tab

自动补全分号,大括号之类: ctrl + shift + enter

查找文件: ctrl + alt + n 告诉他们有三种,以后有机会自己试试

抽取函数

抽取变量

重命名

选中代码 ctrl + W, ctrl + shift + W

回到上一次编辑的地方

查找替换

跳转到函数定义的地方

要训练出的live template有

desc 用于生成describe

test 用于生成it

class 用于生成js的class

extend 用于生成js的extend

m 用于生成js的method

exp 用于生成js的module export

要训练出的macro有

把global函数变成this函数的macro unsurround if

设计部分训练如下:

  1. 打印一行与循环如何分开测试,也可以放在第二问。我一般是让人放在第三问开始考虑,第二问让他坚持自己的惯性思维。第三问发现坚持不下去了。所以也需要亲眼看着发生
  2. 9个测试用例,9种情况-这里对有的人想的会比较快,有的人会想的比较慢,不要直接给出9个case,要让他们自己想到,也许有人会想到超过9种,那是因为其他的几种从纯测试的角度确实应该考虑,但是TDD的角度还是要追求最高性价比
  3. 继承(用继承来消除重复,子类父类只有一个打印单行字符串的地方),抽象思考(getAP和getDP,子类知道weapon和armor,父类不知道,在下一条的null object model的情况下,把“用”字抽象到weapon里去,这也是一个控制反转)与最小知识原则(Person不知道weapon也就不需要判断weapon为空)
  4. NullObject Model(先处理armor,只有一个if,再处理weapon,两个if)
  5. 单例模式(NoArmor和NoWeapon都是单例)
  6. 起名字,会有很多地方要起名字,要求把代码改的可读性更高一些再前进。
  7. 在第三问结束的时候,删掉所有的产品代码用live template和macro重写一遍,不碰鼠标,尽量不使用上下左右。
  8. 角色名应该是类级的属性,然后通过实例方法去访问,而不是在构造的时候构造。主要是思考instance specific和class specific的区别。
  9. 整个循环的流程的测试要让学员明白,这是一个白盒测试,你要知道里面的实现。在这个基础上,你要明白什么是面向接口。也就是我只关心is_alive和

可能的过度设计:

会有人在该返回true/false的时候返回字符串(这种有特定含义的字符串也就是ruby里的symbol,没有特别的意义,不要引入symbol)来表达, 这里面涉及到通识优于自定义的知识这件事情。也就是所谓的常识(指相对我们自己定义的)。 不要觉得这是不对的,只是跟这个题目不贴切,且要用的话,只能是一个大系统当中设计一些小的值定义。

第四问

设计部分训练如下:

  1. 第三问学会的内容的使用,比如继承,null object model, live template,可读性,抽象思考(pre damage string和after damage string, 实际上把过程拆解成时间点是一种对过程的抽象),控制反转(把person的name传给feature生成字符串),快捷键,live template和macro
  2. 过程抽象/封装,很多同学不能意识到把状态触发和攻击封装成一个过程,这说明过程的抽象对于大多数人是比较难以建立起来的认知。
  3. 策略模式
  4. 状态模式,这里有个坑,状态触发的时候,\n放在什么地方,还要考虑多种情况:减血减死了要跳过本轮攻击,眩晕和冰冻发作的时候要跳过本轮攻击。 实际上判断是否触发这事是去不掉的,所以也不要指望靠封装取消掉这个if。为什么要引入状态,而不是直接武器和人都可以持有效果,主要是为了沟通。 如果不引入状态,而是用效果的话,代码倒是写的少了,但是沟通的时候,触发这件事情就要加上更多定语,很容易忘加而造成沟通紊乱。
  5. 工厂模式(由effect产生state)
  6. 时段时刻对象(攻击的一刹那的对象,受伤害的一刹那的对象)(这时引入对时间维度建模)(当然会有人因此变得想要引入更多)

可能的过度设计: 引入Battle对象处理每一轮 引入计时对象记录效果还剩几轮


Fork me on GitHub