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

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

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

今回はProxyパターンです。

内部的に処理が違うものをプロキシを立てることによってユーザは意識せずに使えるようにするパターンの様です。

毎度例がfibばかりなのですが、Nが30より大きくなると高速版に切り換えるようなものを作成してみました。

例のための例という感じですが…。

とりあえず、今回で色々悩みつつ実習してきた「CLとデザインパターン」今回でGoFの23パターンを制覇できました。

感想としては、Norvig氏のDesign Patterns in Dynamic Programmingでも述べられていますが、生成に関しては、ファースト・クラスの型(クラス)、振舞いに関しては、ファースト・クラスの関数がある場合、実行したいことが分かっているならクラスの構成を色々工夫しなくてもストレートに表現できるかなと思いました。

また、ウェブで参照できる入門的なテキストは殆どJavaやC++なのでこれらの例を翻訳して考えるのに割と苦戦しました。

上記のNorvig氏のプレゼンでは、動的言語ならではのパターンというものが提案されているので、今後はこれをさらって行こうかと思います。

(defclass subject () ())

(defclass proxy (subject) ())
(defclass real-subject (subject) ())

(defgeneric fib (class n))
;; Proxy(基本的に低速 N > 30 で高速版に処理を投げる)
(defmethod fib ((class proxy) n)
  (let ((class 
         (if (< 30 n)
             (change-class class 'real-subject)
             class)))
    (if (< n 2)
        n
        (+ (fib class (1- n))
           (fib class (- n 2))))))
;; 高速版
(defmethod fib ((class real-subject) n)
  (labels ((*fib (n a1 a2)
             (if (< n 2)
                 a1
                 (*fib (1- n) 
                       (+ a1 a2)
                       a1))))
    (*fib n 1 0)))

;; 試してみる
(time (fib (make-instance 'proxy)
     100))
;   Evaluation took:
;     0.002 seconds of real time
;     0.000000 seconds of total run time (0.000000 user, 0.000000 system)
;     0.00% CPU
;     6 forms interpreted
;     3,022,236 processor cycles
;     31,856 bytes consed
;=> 354224848179261915075

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

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

今回はFlyweightパターンです。

Mementoと似た感じで違いが良く分からないのですが、インスタンスの生成に使うのがポイントなんでしょうか。

ということで、普通のフィボナッチ関数に無理矢理メモワイズ機能をつけてみました。

下記のfibクラスはフィボナッチ関数の結果を格納するだけの為に存在していて、要求の分だけインスタンスが作られますが、既に結果を含むインスタンスがあった場合は、それが使い回されます。

fibmeのaroundメソッドがFactoryな感じで考えています。

(defclass memento () 
  ((mementoes :initform (make-hash-table :test #'equal) 
              :accessor mementoes)))

(defclass fib () 
  ((ans :initarg :ans :accessor ans)))

(defgeneric fibme (memento n))
(defmethod fibme ((m memento) n)
  (if (< n 2)
      n
      (+ (fibme m (1- n))
         (fibme m (- n 2)))))

(defmethod fibme :around ((m memento) n)
  (symbol-macrolet ((mem (gethash n (mementoes m))))
    (if mem
        (ans mem)
        (let ((ans (call-next-method)))
          (setf mem (make-instance 'fib :ans ans))
          ans))))

(let ((m (make-instance 'memento)))
  (fibme m 100))
;=> 354224848179261915075