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-18

CLとデザインパターン - Chain of Responsibility

| 18:05 | CLとデザインパターン - Chain of Responsibility - わだばLisperになる を含むブックマーク はてなブックマーク - CLとデザインパターン - Chain of Responsibility - わだばLisperになる

今回はChain of Responsibilityパターンです。

メソッドが処理可能かを調べて順繰りに処理可能なメソッドを探して起動というパターンのようです。

説明を読んだ限りでは、メソッドコンビネーションのorが使えるような気がしたので、それで書いてみました。

メソッドコンビネーションのorは、特定度の高いところから結果が非nilになるまでメソッドを探して実行するもので、まさにピッタリという気がしたのですが、Norvig氏のDesign Patterns in Dynamic Programmingでも、Greg Sullivan氏のGOF Design Patterns in a Dynamic OO Languageでもメソッドコンビネーションに触れられてはいませんでした。自分は何か勘違いしているのかも…。

(defclass level-1 () ())
(defclass level-2 (level-1) ())
(defclass level-3 (level-2) ())

(defgeneric action-1 (class)
  (:method-combination or))
(defmethod action-1 or ((class level-1))
  (print "level-1!"))

(defgeneric action-2 (class)
  (:method-combination or))
(defmethod action-2 or ((class level-3))
  (print "level-3!"))

(defgeneric action-3 (class)
  (:method-combination or))
(defmethod action-3 or ((class level-2))
  (print "level-2!"))
(defmethod action-3 or ((class level-1))
  (print "level-1!"))

(let ((inst (make-instance 'level-3)))
  (action-1 inst)
  (action-2 inst)
  (action-3 inst))
;-> "level-1!" 
;   "level-3!" 
;   "level-2!" 

メソッドコンビネーションを使うからには、クラスの優先順位で状態が移行して行くわけで、クラスの優先順位は関係なく起動したいという場合を考えて、優先順位を付けるためだけに別にクラスを定義して対応するというのも考えてみました。これには多重継承の仕組みを利用していて、基本設定では、左に記述されているものが優先されることを利用して優先度を記述します。

(defclass foo () ())
(defclass bar () ())
(defclass baz () ())

(defclass handler (foo bar baz) ())

(defgeneric foo (class)
  (:method-combination or))
(defmethod foo or ((class foo))
  (print "foo"))

(defgeneric baz (class)
  (:method-combination or))
(defmethod baz or ((class baz))
  (print "baz"))

(defgeneric bar (class)
  (:method-combination or))
(defmethod bar or ((class bar))
  (print "bar"))
(defmethod bar or ((class baz))
  ;; bar クラスの定義があると実行されない
  (print "baz"))

;;; 実行例
(let ((inst (make-instance 'handler)))
  (foo inst)
  (bar inst)
  (baz inst))
;-> "foo" 
;   "bar" 
;   "baz" 

;; 優先順位を変更したものを作成
(defclass handler2 (baz foo bar) ())

(let ((inst (make-instance 'handler2)))
  (foo inst)
  (bar inst)
  (baz inst))
;-> "foo" 
;   "baz" 
;   "baz" ;handlerのケースとは逆転した

ゲスト



トラックバック - http://cadr.g.hatena.ne.jp/g000001/20081218