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

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

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

今回はPrototypeパターンです。

インスタンスをコピーできるような仕組みを準備して便利に使おう、というパターンのようです。

Smalltalkでは、標準でコピーできるのだそうです。CLにもありそうでしたが、無いので自作しました。

新しいインスタンスを作ってスロットの内容をコピーするという素朴なものです。

総称関数ベースなのでどうもクラスがコピー関数を提供するというよりは、コピー可能属性をprototype-mixinで付与する位の感覚になっていますが、そもそも、prototype-mixinを作るまでもなく全部に総称関数を適用すればOKです。もしくは、普通の関数でコピーする機能を実装しても良いんじゃないかとも思うのですが、どうなのでしょう。

コピーには浅いコピーと深いコピーがあるようなのですが、slot-valueを使用すると浅いコピーになるようなので下記のコードも浅いコピーです。

この辺は、slot-value-deep-copyを作ってみたり、deep-copy-mixinクラスを作ってディスパッチしたりできそうですが、CLの場合、使う時に利用者の判断でコピーしたりする気もします。

(defclass prototype-mixin () ())

(defgeneric clone (inst))
(defmethod clone ((inst prototype-mixin))
  (let* ((class (class-of inst))
         (new (make-instance class)))
    (map nil (lambda (x) 
               (setf (slot-value new x)
                     (slot-value inst x)))
         (mapcar #'c2mop:slot-definition-name
                 (c2mop:class-slots class)))
    new))

(defclass foo (prototype-mixin)
  ((x :initarg :x)
   (y :initarg :y)
   (z :initarg :z)))

(defclass bar (foo)
  ((a :initform 0)))

(defclass baz (bar)
  ((b :initform 1)))

(let ((x (make-instance 'baz :x 10 :y 20 :z 30)))
  (map nil #'describe (list x (clone x))))

;=> #<BAZ 2008C12B> is a BAZ
;   B      1
;   A      0
;   X      10
;   Y      20
;   Z      30
;=> #<BAZ 2008BFB7> is a BAZ
;   B      1
;   A      0
;   X      10
;   Y      20
;   Z      30

ゲスト



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