[racket] Visitor Pattern and Racket
"A Little Java a Few Patterns" gives a simple example of the Visitor
Pattern which collects the variations of a method over different
sub-class variations into its own class. The classes recursively
define a shish-kabob and the method says if it only contains onions?
Case 1 below is my version in Racket, but I can just as easily in
Racket (I don't know about other languages) collect the variations in
the main class as in case 2 below which seems much simpler, or even
collect the variations of the method in a mixin as in case 3.
Does the Visitor pattern give something that collecting the methods in
the main class or using a mixin doesn't? Or do the class features of
Racket, particularly mixins make the Visitor Pattern superfluous?
Thanks,
Harry Spier
Case 1: Visitor Pattern
#lang racket
(define shish-D%
(class object% (super-new)
(define/public (only-onions-fn)
(new only-onions-visitor%))
(abstract only-onions?)))
(define shish-D%/c (is-a?/c shish-D%))
(define skewer%
(class shish-D% (super-new)
(inherit only-onions-fn)
(define/override (only-onions?)
(send (only-onions-fn) for-skewer))))
(define/contract onion%
(class/c [init (sh shish-D%/c)])
(class shish-D% (super-new)
(init-field sh)
(inherit only-onions-fn)
(define/override (only-onions?)
(send sh only-onions?))))
(define/contract lamb%
(class/c [init-field (sh shish-D%/c)])
(class shish-D% (super-new)
(init-field sh)
(inherit only-onions-fn)
(define/override (only-onions?)
(send (only-onions-fn) for-lamb))))
(define/contract tomato%
(class/c [init-field (sh shish-D%/c)])
(class shish-D% (super-new)
(init-field sh)
(inherit only-onions-fn)
(define/override (only-onions?)
(send (only-onions-fn) for-tomato))))
(define only-onions-visitor%
(class object% (super-new)
(define/public (for-skewer) #t)
(define/public (for-lamb) #f)
(define/public (for-tomato) #f)
(define/public (for-onion shish)
((send shish only-onions? )))))
(define shish-a (new onion% [sh (new onion% [sh (new skewer%)])]))
(define shish-b (new onion% [sh (new lamb% [sh (new skewer%)])]))
(define shish-c (new onion% [sh (new onion% [sh (new lamb% [sh (new
skewer%)])])]))
(send shish-a only-onions? )
(send shish-b only-onions? )
(send shish-c only-onions? )
Case 2: Collecting the method variations in the main class
#lang racket
(define shish-D%
(class object% (super-new)
(init-field sh)
(define/public (only-onions?)
(cond
[(is-a? this skewer%) #t]
[(is-a? this lamb%) #f]
[(is-a? this tomato%) #f]
[(is-a? this onion%)
(send sh only-onions? )]))))
(define shish-D%/c (is-a?/c shish-D%))
(define/contract skewer%
(class/c [field (sh #f)])
(class shish-D% (super-new)
(inherit only-onions?)))
(define/contract onion%
(class/c [init-field (sh shish-D%/c)])
(class shish-D% (super-new)
(inherit only-onions?)))
(define/contract lamb%
(class/c [init-field (sh shish-D%/c)])
(class shish-D% (super-new)
(inherit only-onions?)))
(define/contract tomato%
(class/c [init-field (sh shish-D%/c)])
(class shish-D% (super-new)
(inherit only-onions?)))
(define shish-a (new onion% [sh (new onion% [sh (new skewer% [sh #t])])]))
(define shish-b (new onion% [sh (new lamb% [sh (new skewer% [sh #f])])]))
(define shish-c (new onion% [sh (new onion% [sh (new lamb% [sh (new
skewer% [sh #f])])])]))
(send shish-a only-onions?)
(send shish-b only-onions?)
(send shish-c only-onions?)
Case 3: Collecting the method variations in a mixin
#lang racket
(define (only-onions-mixin %)
(class % (super-new)
(init-field sh)
(define/public (only-onions?)
(cond
[(is-a? this skewer%) #t]
[(is-a? this lamb%) #f]
[(is-a? this tomato%) #f]
[(is-a? this onion%)
(send sh only-onions? )]))))
(define shish-D%
(class object% (super-new)))
(define shish-D%/c (is-a?/c shish-D%))
(define/contract skewer%
(class/c [field (sh #f)])
(class (only-onions-mixin shish-D%)(super-new)
(inherit only-onions?)))
(define/contract onion%
(class/c [init-field (sh shish-D%/c)])
(class (only-onions-mixin shish-D%)(super-new)
(inherit only-onions?)))
(define/contract lamb%
(class/c [init-field (sh shish-D%/c)])
(class (only-onions-mixin shish-D%)(super-new)
(inherit only-onions?)))
(define/contract tomato%
(class/c [init-field (sh shish-D%/c)])
(class (only-onions-mixin shish-D%)(super-new)
(inherit only-onions?)))
(define shish-a (new onion% [sh (new onion% [sh (new skewer% [sh #t])])]))
(define shish-b (new onion% [sh (new lamb% [sh (new skewer% [sh #f])])]))
(define shish-c (new onion% [sh (new onion% [sh (new lamb% [sh (new
skewer% [sh #f])])])]))
(send shish-a only-onions?)
(send shish-b only-onions?)
(send shish-c only-onions?)