こんにちは!! tahara です。 Lisp on Rails 第6回です!
has-one を has-many のコピペで書いてしまったので、 ここらでリファクタリングしたいと思います。
has-one のスロット定義
(defclass ar-has-one-slot-mixin () ((has-one :initarg :has-one :initform nil :accessor has-one) (class-symbol :initarg :class-symbol :initform nil :accessor class-symbol))) (defmethod initialize-instance :after ((self ar-has-one-slot-mixin) &rest args) (declare (ignore args)) (unless (class-symbol self) (setf (class-symbol self) (has-one self)))) (defclass ar-has-one-direct-slot-definition (ar-direct-slot-definition ar-has-one-slot-mixin) ()) (defclass ar-has-one-effective-slot-definition (ar-effective-slot-definition ar-has-one-slot-mixin) ())
has-many のスロット定義
(defclass ar-has-many-slot-mixin () ((has-many :initarg :has-many :initform nil :accessor has-many) (class-symbol :initarg :class-symbol :initform nil :accessor class-symbol))) (defmethod initialize-instance :after ((self ar-has-many-slot-mixin) &rest args) (declare (ignore args)) (unless (class-symbol self) (setf (class-symbol self) (sym (singularize (has-many self)))))) (defclass ar-has-many-direct-slot-definition (ar-direct-slot-definition ar-has-many-slot-mixin) ()) (defclass ar-has-many-effective-slot-definition (ar-effective-slot-definition ar-has-many-slot-mixin) ())
いやー、ひどいですね。 ほとんど one と many の違いだけです。
さて、これをリファクタリングするのに Common Lisp にはマクロという手抜きプログラマには必須の機能があります。
普通リファクタリングするとなると、関数、メソッド、スーパークラス等々の 切り出しが必要になりますよね? でも、マクロなら何ら設計を変更することなくリファクタリングが可能になります。
では、実際にマクロを使ってリファクタリングしてみましょう。
(defmacro def-has-xxx-slot-definition (xxx default-class-symbol-form) `(progn (defclass ,(sym "ar-has-" xxx "-slot-mixin") () ((,(sym "has-" xxx) :initarg ,(key-sym "has-" xxx) :initform nil :accessor ,(sym "has-" xxx)) (class-symbol :initarg :class-symbol :initform nil :accessor class-symbol))) (defmethod initialize-instance :after ((self ,(sym "ar-has-" xxx "-slot-mixin")) &rest args) (declare (ignore args)) (unless (class-symbol self) (setf (class-symbol self) ,default-class-symbol-form))) (defclass ,(sym "ar-has-" xxx "-direct-slot-definition") (ar-direct-slot-definition ,(sym "ar-has-" xxx "-slot-mixin")) ()) (defclass ,(sym "ar-has-" xxx "-effective-slot-definition") (ar-effective-slot-definition ,(sym "ar-has-" xxx "-slot-mixin")) ()) )) (def-has-xxx-slot-definition one (has-one self)) (def-has-xxx-slot-definition many (sym (singularize (has-many self))))
すばらい。 最初のひどい設計を何ら変えることなくリファクタリングできました。
手抜き設計のベタ書きコードそのままで、リファクタリングを可能とするマクロは、 未熟なプログラマにとって、なくてはならない存在です。
ソースはこちらから http://github.com/quek/lisp-on-rails
第7回につづきます。