消息传递
介绍消息传递:把类型表示为函数、数据表示为对象,奠定面向对象编程的基础。
什么是消息传递?
在传统风格中,运算符被表示为了解不同类型的函数,而类型本身只是数据。在数据导向编程中,运算符和类型都是数据,有一个通用的 operate 函数包揽所有工作。我们也可以把传统风格整个颠倒过来:把类型表示为函数,把操作仅仅当作数据。
事实上,不仅类型是函数,每一条数据本身也是函数。也就是说,有一个函数(下面的 make-circle)代表圆形类型;当你调用这个函数时,它返回另一个函数,代表你作为实参传给它的那个特定的圆。每个圆都是一个对象(object),而代表它的那个函数是一个分派过程(dispatch procedure),它接受一个消息作为实参,用来说明要执行哪个操作。
make-square 和 make-circle 的新定义如下:
(define (make-square side)
(lambda (message)
(cond ((eq? message 'area)
(* side side))
((eq? message 'perimeter)
(* 4 side))
(else (error "Unknown message")))))
(define (make-circle radius)
(lambda (message)
(cond ((eq? message 'area)
(* pi radius radius))
((eq? message 'perimeter)
(* 2 pi radius))
(else (error "Unknown message")))))
(define square5 (make-square 5))
(define circle3 (make-circle 3))
消息传递为什么重要?
消息传递看起来可能是处理形状问题的一种过于复杂的方式,但我们将在下一课看到,它是构建面向对象编程的关键思想之一。消息传递与局部状态(local state)的思想结合起来(我们下周会学到)之后,会变得强大得多。
我们似乎已经放弃了带标签数据:每种形状类型都只是某个函数,很难判断一个给定的函数代表哪种形状。如果愿意的话,我们可以给每个对象加一个 type 消息,把消息传递和带标签数据结合起来:
(define (make-square side)
(lambda (message)
(cond ((eq? message 'area)
(* side side))
((eq? message 'perimeter)
(* 4 side))
((eq? message 'type) 'square)
(else (error "Unknown message")))))