带有显式分派的通用性操作
在加入一个新类型时,需要添加新类型的构造过程、选择过程、各自通用操作过程,另外还需要在通用操作过程中加入数据标识的判断,根据数据标识执行相应的数据类型过程。
而如果需要添加新操作,则需要在每一种类型里面添加各自的新的操作,还需要添加新操作的通用过程。
拿书中复数的实现举例添加新类型需要修改的编码。
#lang racket
//加入新类型的构造过程和选择过程
(define (real-part-polar z)
(* (magnitude-polar z) (cos (angle-polar z))))
(define (imag0part-polar z)
(* (magnitude-polar z) (sin (angle-polar z))))
(define (magintude-polar z) (car z))
(define (angle-polar z) (cdr z))
(define (make-from-real-imag-polar x y)
(attach-tag 'polar
(cons (sqrt (+ (square x) (square y)))
(atan y x))))
(define (make-from-mag-ang-polar r a)
(attach-tag 'polar (cons r a)))
//加入标识判断
(define (reak-part z)
(cond ((rectangular? z)
(real-part-rectangular (contents z)))
((polar? z)
(real-part-polar (contents z)))
(else (error "Unknown type -- REAL-PART" z))))
不论添加新类型还是新操作都需要修改大量代码来实现。
数据向导风格
在加入一个新类型时,需要添加新类型的过程包就可以,其他地方不需要变动。
#lang racket
(define (install-polar-package)
(define (magnitude z) (car z))
(define (angle z) (cdr z))
(define (make-from-mag-ang r a) (cons r a))
(define (real-part z)
(* (magnitude z) (cos (angle z))))
(define (imag-part z)
(* (magnitude z) (sin (angle z))))
(define (make-from-real-imag x y)
(cons (sqrt (+ (square x) (square y)))
(atan y x)))
(define (tag x) (attach-tag 'polar x))
(put 'real-part '(polar) real-part)
(put 'imag-part '(polar) imag-part)
(put 'magnitude '(polar) magnitude)
(put 'angle '(polar) angle)
(put 'make-from-real-imag '(polar)
(lambda (x y) (tag (make-from-real-imag x y))))
(put make-from-mag-ang '(polar)
(lambda (r a) (tag (make-from-mag-ang r a))))
'done)
如果添加新操作,也可以添加一个安装包,这个安装包里面包含每一种类型对应新操作的过程,比如下面这种方式。
(define (install-newop-package)
(define (newop-rectangular z)
(car z))
(define (newop-polar z)
(car z))
(put 'newop '(rectangular) newop-rectangular)
(put 'newop '(polar) newop-polar))
(define (newop z) (apply-generic 'newop z))
这种方式有操作信息表,比较灵活,不管是添加新类型或者新操作,只要操作“操作信息表”就可以。
消息传递的风格
在加入一个新类型时,需要添加新类型的构造程序就可以,其他地方不需要变动。
(define (make-from-mag-ang r a)
(define (dispatch op)
(cond ((eq? op 'real-part) (* r (cos a)))
((eq? op 'imag-part) (* r (sin a)))
((eq? op 'magnitude) r)
((eq? op 'angle) a)
(else
(error "Unknown op -- MAKE-FROM-MAG-ANG" op))))
dispatch)
如果添加新操作,则需要每一个构造过程加入新的操作函数。
(define (make-from-mag-ang r a)
(define (dispatch op)
(cond ((eq? op 'real-part) (* r (cos a)))
((eq? op 'imag-part) (* r (sin a)))
((eq? op 'magnitude) r)
((eq? op 'angle) a)
((eq? op 'newop) (square r))
(else
(error "Unknown op -- MAKE-FROM-MAG-ANG" op))))
dispatch)
消息传递的风格,不需要过多的选择函数,代码量比较小,但是添加新操作比较麻烦,每种都需要添加。