Lisp on Rails 第6回 〜 ここらでリファクタリング

区分
LisponRails
報告者

こんにちは!! 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回につづきます。

トップページに戻る

技師部隊からの
お知らせ

【求人】エンジニア募集しています。

本頁の来客数
八十七万千百七十六名以上(計測停止中)

メンバー一覧

アクトインディ技師部隊員名簿

アクトインディ技師部元隊員

アクトインディへ

カテゴリー

アクトインディ

aaaa