项目 3:搭档 B 进阶练习
Project 3 中搭档 B 的第二部分练习(B6–B8):食物类、警察类与改进的 take 机制。
第 B6 题:第一部分
我们目前让人们从餐馆拿食物的方式在几个方面都不真实。本周的总体目标就是修正它。第一步,你要创建一个 food 类。我们给食物两个属性:edible? 属性和 calories 属性。如果对象是食物,edible? 的值为 #t。如果一个 person 吃了一些 food,这些食物的 calories 会加到这个人的 strength 上。
(记住,由于第 B4 题中属性的实现方式,edible? 属性对食物以外的对象会自动是 false。你不必挨个告诉其他东西都不能吃。)
请写一个 food 类的定义,它以 thing 作为父类。给它发 edible? 消息时它应当返回 #t,并且应当能正确响应 calories 消息。
把原 adv.scm 里名为 edible? 的过程替换成一个新版本,利用你创建的机制,而不是依赖内置的食物类型列表。
> (define pesto-pasta (instantiate food 'pasta 150))
;名字是 pesto-pasta,热量是 150
> (ask pesto-pasta 'calories)
150
> (ask pesto-pasta 'edible?)
#t
> (edible? pesto-pasta)
#t
第 B6 题:第二部分
有了 food 类之后,再发明一些特定种类食物的子类。例如,做一个继承自 food 的 pasta 类。pasta 不应当有任何实例化变量。给 pasta 一个类变量(class variable)name,值为单词 pasta。(以后发明 restaurant 对象时我们会用到它。)
用你的 pasta 类,现在应当可以这样实例化上面的 pesto-pasta:
> (define pesto-pasta (instantiate pasta))
> (ask pesto-pasta 'calories)
150
第 B6 题:第三部分
给人物的 eat 方法。你的 eat 方法应当查看你的 possessions,过滤出所有可食用的。然后把这些食物的 calories 值加到你的 strength 上。接着让这些食物消失(既不再是你的 possessions,也不再在你的所在地点)。
合并工作
继续之前,请让搭档讲解第 A6 题及其解答。同时,也向你的搭档讲解第 B6 题及其解答。
第 B7 题
你的任务是定义 police 类。当警察注意到有新的人进入他所在的地方,他会检查此人是不是小偷。如果此人是小偷,警察就说「Crime Does Not Pay」(犯罪划不来),然后没收小偷的所有财物,并把他直接送进监狱。
给小偷和警察默认的 strength。小偷起步应比普通人强,但警察应比小偷强。当然,如果你吃很多东西,就能攒够 strength,从小偷手里抢回食物。
请测试你的代码,并提交一份操作记录,展示小偷偷你的食物、你追赶小偷、警察抓住小偷的过程。万一你没注意到——我们已经在 Sproul Plaza 放了一个小偷,方便你测试代码。
> (define somepolice (instantiate police 'grammarpolice soda))
第 B8 题
现在我们要重组 take,让它先看看谁之前持有想要的物品。如果持有者是 'no-one,就照老规矩直接拿。否则,调用:
> (ask thing 'may-take? receiver)
属于某个人的物品,其 may-take? 方法应当比较持有者与请求者的 strength,决定能不能被拿走。如果接收者和持有者 strength 相同,接收者可以拿走该物品。如果物品没有持有者,接收者可以拿走该物品。
如果人物不能拿走物品,方法应返回 #f;如果可以拿走,返回物品本身。就目前而言,这比必要的复杂度稍高,但我们在为将来做准备——比如,将来某个对象可能想为自己克隆一个副本来让人拿走。
注意这里消息传递的纷繁往来:我们给拿东西的人发消息,它给物品发消息,物品又给两个人发消息,打听他们的 strength。