5.3 类
虽然我们的确实现了方法定义的共享,但是这个解决方案并不理想。为什么?观察对象的定义(上述 (λ (msg . args) ....)
的函数体)。在那里实现的逻辑在所有用 make-point
创建对象中都是重复的:每个对象都有它自己的副本,当它收到 -read
消息时,在 fields
字典中查找; -write
消息时,更新 fields
字典;任何其他消息,查找 methods
表,然后应用对应方法。
所以说,所有这些逻辑在对象之间都可以共享。对象体中唯一的自由变量是 fields
和 self
。换句话说,我们可以把对象定义为它自己外加它的字段,而把所有其他的逻辑都交给 make-point
函数。这样的话, make-point
的功能不再是单一的只负责创建新的对象,还负责处理对字段的访问和对消息的处理。也就是说, make-point
演变成所谓的 类 (class)。
我们如何表示类?目前它只是可以调用的函数(它会创建对象——一个 实例 );如果需要该函数有不同的行为,我们可以应用本书开始时看到的 对象模式 。
在某些语言中,类本身就是对象。这方面的范例就是 Smalltalk。绝对值得花时间一学!
于是:
(define Point
....
(λ (msg . args)
(case msg
[(create) create instance]
[(read) read field]
[(write) write field]
[(invoke) invoke method])))
这种模式明确了类的作用:它产生对象,调用方法,读取和写入其实例的字段。
现在,对象的作用是什么?他只需要有标识(identity)功能,知道自己属于哪个类,并记录自己的字段值。它不再自带任何行为。换种说法,对象可以定义为普通的数据结构:
(define-struct obj (class values))
接下来看看现在该怎么定义 Point 类:
(define Point
(let ([methods ....])
(letrec
([class
(λ (msg . vals)
(case msg
[(create) (let ((values (make-hash '((x . 0)))))
(make-obj class values))]
[(read) (dict-ref (obj-values (first vals))
(second vals))]
[(write) (dict-set! (obj-values (first vals))
(second vals)
(third vals))]
[(invoke)
(let ((found (assoc (second vals) methods)))
(if found
(apply ((cdr found) (first vals)) (cddr vals))
(error "message not understood")))]))])
class)))
> (Point 'create)
#<obj>
要实例化 Point
类,只需向其发送 create
消息。现在对象是结构体了,我们需要一种方法来发送消息,还有访问其字段。要向对象 p
发送消息,先要检索它的类,然后给这个类发送 invoke
消息:
((obj-class p) 'invoke p 'x?)
访问字段也是类似。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论