Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2008-12-17

CLとデザインパターン - Visitor

| 10:15 | CLとデザインパターン - Visitor - わだばLisperになる を含むブックマーク はてなブックマーク - CLとデザインパターン - Visitor - わだばLisperになる

今回はVisitorです。

Norvig氏のDesign Patterns in Dynamic Programmingでは、ファーストクラスの関数で対処可能。Greg Sullivan氏のGOF Design Patterns in a Dynamic OO Languageによれば、多重ディスパッチで解決できるとのこと。自分の感じだと、どちらかというとVisitorという名前からしてファースト・クラスの関数を引数に与えて内部で実行という方がしっくり来ます。

とりあえず、普通のものと、多重ディスパッチのものと2つ書いてみました。

;; aceptor
(defclass fruit-shop () 
  ((fruit :initform '("リンゴ" "ミカン" "バナナ") :reader fruit)))

(defclass fruit-shop2 (fruit-shop) 
  ((fruit :initform '("いちご" "キウイ" "メロン") :reader fruit)))

;; visitor
(defclass salesman () 
  ((fruit-shop :accessor fruit-shop)))

(defgeneric bargain-sale (salesman)
  (:method ((salesman salesman))
    (format T "~{~Aが安いよ!~%~}" (fruit (fruit-shop salesman)))))

(defgeneric ask-visitor (fruit-shop salesman))

;; single dispatch
(defmethod ask-visitor ((fruit-shop fruit-shop) salesman)
  (setf (fruit-shop salesman) fruit-shop)
  (bargain-sale salesman))

(defclass salesman2 (salesman) ())

(defmethod bargain-sale ((salesman salesman2))
  (format T "~{~Aがとんでもなく安いよ!~%~}" (fruit (fruit-shop salesman))))

;;; 実行してみる
(let ((fs (make-instance 'fruit-shop))
      (v (make-instance 'salesman)))
  (ask-visitor fs v))
;-> リンゴが安いよ!
;   ミカンが安いよ!
;   バナナが安いよ!
;=> NIL

(let ((fs (make-instance 'fruit-shop))
      (v (make-instance 'salesman2)))
  (ask-visitor fs v))

;-> リンゴがとんでもなく安いよ!
;   ミカンがとんでもなく安いよ!
;   バナナがとんでもなく安いよ!
;=> NIL

(let ((fs (make-instance 'fruit-shop2))
      (v (make-instance 'salesman2)))
  (ask-visitor fs v))
;-> いちごがとんでもなく安いよ!
;   キウイがとんでもなく安いよ!
;   メロンがとんでもなく安いよ!
;=> NIL

;; ==========================
;; 多重ディスパッチ版
(defclass fruit-shop () 
  ((fruit :initform '("リンゴ" "ミカン" "バナナ") :reader fruit)))

(defclass fruit-shop2 (fruit-shop) 
  ((fruit :initform '("いちご" "キウイ" "メロン") :reader fruit)))

(defclass salesman-md () ())
(defclass salesman-md2 (salesman-md) ())

(defgeneric bargain-sale-md (salesman-md fruit-shop))
(defmethod bargain-sale-md ((s salesman-md) (fs fruit-shop))
  (format T "~{~Aが安いよ!~%~}" (fruit fs)))
(defmethod bargain-sale-md ((s salesman-md2) (fs fruit-shop))
  (format T "~{~Aがとんでもなく安いよ!~%~}" (fruit fs)))
(defmethod bargain-sale-md ((s salesman-md) (fs fruit-shop2))
  (format T "~{~Aが新鮮だよ!~%~}" (fruit fs)))
(defmethod bargain-sale-md ((s salesman-md2) (fs fruit-shop2))
  (format T "~{~Aがとんでもなく新鮮だよ!~%~}" (fruit fs)))

(let ((fs (make-instance 'fruit-shop))
      (s (make-instance 'salesman-md)))
  (bargain-sale-md s fs))
;-> リンゴが安いよ!
;   ミカンが安いよ!
;   バナナが安いよ!
;=> NIL

(let ((fs (make-instance 'fruit-shop2))
      (s (make-instance 'salesman-md2)))
  (bargain-sale-md s fs))
;-> いちごがとんでもなく新鮮だよ!
;   キウイがとんでもなく新鮮だよ!
;   メロンがとんでもなく新鮮だよ!
;=> NIL