smithery.ai

cl-clos-patterns

CLOS設計パターンを適用。クラス設計・メソッド実?

First seen Mar 22, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Allowed toolsRead, Grep, Glob

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 6,732 B
  • docs SUMMARY.md 106 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

CLOS Design Patterns

クラス定義

基本構造

(defclass user ()
  ((id
    :initarg :id
    :reader user-id
    :type integer
    :documentation "Unique identifier")
   (name
    :initarg :name
    :accessor user-name
    :type string
    :documentation "Display name")
   (email
    :initarg :email
    :accessor user-email
    :type string)
   (created-at
    :initform (get-universal-time)
    :reader user-created-at
    :type integer)
   (active-p
    :initarg :active-p
    :initform t
    :accessor user-active-p
    :type boolean))
  (:documentation "Represents a user account."))

スロットオプション

オプション 用途
:initarg コンストラクタ引数
:initform デフォルト値
:reader 読み取り専用アクセサ
:writer 書き込み専用アクセサ
:accessor 読み書きアクセサ
:type 型宣言(最適化ヒント)
:allocation :instance または :class
:documentation ドキュメント

アクセサの使い分け

;; :reader - 変更不可のID
(id :initarg :id :reader user-id)

;; :accessor - 変更可能な属性
(name :initarg :name :accessor user-name)

;; :writer のみ - 稀なケース
(password-hash :writer (setf user-password-hash))

継承

単一継承

(defclass person ()
  ((name :initarg :name :accessor person-name)))

(defclass employee (person)
  ((employee-id :initarg :employee-id :reader employee-id)
   (department :initarg :department :accessor employee-department)))

多重継承

(defclass named-mixin ()
  ((name :initarg :name :accessor object-name)))

(defclass timestamped-mixin ()
  ((created-at :initform (get-universal-time) :reader created-at)
   (updated-at :initform (get-universal-time) :accessor updated-at)))

(defclass document (named-mixin timestamped-mixin)
  ((content :initarg :content :accessor document-content)))

クラス優先順位 (CPL)

;; C3線形化でメソッド解決順序を決定
(defclass a () ())
(defclass b (a) ())
(defclass c (a) ())
(defclass d (b c) ())  ; CPL: d -> b -> c -> a -> standard-object -> t

メソッド定義

基本メソッド

(defgeneric process (object)
  (:documentation "Process the given object."))

(defmethod process ((obj user))
  (format t "Processing user: ~A~%" (user-name obj)))

(defmethod process ((obj document))
  (format t "Processing document: ~A~%" (object-name obj)))

メソッド組み合わせ

:before / :after

;; メインメソッドの前後に実行
(defmethod process :before ((obj user))
  (log:info "Starting process for user ~A" (user-id obj)))

(defmethod process :after ((obj user))
  (log:info "Finished process for user ~A" (user-id obj)))

:around

;; メインメソッドをラップ
(defmethod process :around ((obj user))
  (let ((start (get-internal-real-time)))
    (prog1 (call-next-method)  ; メインメソッドを呼び出し
      (log:debug "Process took ~Dms"
                 (- (get-internal-real-time) start)))))

実行順序

:around (外側)
  :before (CPL順)
    primary (最も特化)
  :after (CPL逆順)
:around (内側に戻る)

特化子 (Specializer)

クラス特化

(defmethod draw ((shape circle))
  ...)

EQL特化

(defmethod handle-event ((event (eql :click)))
  (format t "Click event~%"))

(defmethod handle-event ((event (eql :keypress)))
  (format t "Keypress event~%"))

初期化プロトコル

initialize-instance

(defmethod initialize-instance :after ((user user) &key)
  ;; IDが未指定なら生成
  (unless (slot-boundp user 'id)
    (setf (slot-value user 'id) (generate-id)))
  ;; バリデーション
  (unless (valid-email-p (user-email user))
    (error "Invalid email: ~A" (user-email user))))

make-instance のカスタマイズ

;; ファクトリ関数を提供
(defun make-user (name email &key (active-p t))
  "Create a new user with validation."
  (make-instance 'user
                 :name name
                 :email email
                 :active-p active-p))

reinitialize-instance

(defmethod reinitialize-instance :after ((user user) &key)
  (setf (updated-at user) (get-universal-time)))

;; 使用
(reinitialize-instance user :name "New Name")

設計パターン

パターン1: プロトコル (Interface)

;; 抽象プロトコル
(defgeneric serialize (object stream)
  (:documentation "Serialize object to stream."))

(defgeneric deserialize (class stream)
  (:documentation "Deserialize object from stream."))

;; 実装
(defmethod serialize ((user user) stream)
  (format stream "~A:~A:~A"
          (user-id user)
          (user-name user)
          (user-email user)))

パターン2: Mixin

(defclass validatable-mixin ()
  ())

(defgeneric validate (object)
  (:method-combination progn))

(defmethod validate progn ((obj validatable-mixin))
  ;; 基本バリデーション
  t)

(defclass user (validatable-mixin)
  (...))

(defmethod validate progn ((user user))
  (assert (valid-email-p (user-email user))))

パターン3: ビジター

(defgeneric visit (visitor object)
  (:documentation "Visit object with visitor."))

(defclass print-visitor () ())

(defmethod visit ((v print-visitor) (u user))
  (format t "User: ~A~%" (user-name u)))

(defmethod visit ((v print-visitor) (d document))
  (format t "Document: ~A~%" (object-name d)))

パターン4: シングルトン

(defclass configuration ()
  ((instance :allocation :class :initform nil)))

(defun get-configuration ()
  (or (slot-value (find-class 'configuration) 'instance)
      (setf (slot-value (find-class 'configuration) 'instance)
            (make-instance 'configuration))))

ベストプラクティス

1. defgeneric を明示

;; Good - 明示的なジェネリック定義
(defgeneric process (object)
  (:documentation "Process the object."))

(defmethod process ((obj user))
  ...)

;; Bad - 暗黙的なジェネリック
(defmethod process ((obj user))
  ...)

2. 適切なアクセサ選択

;; 変更不可 -> :reader
;; 変更可能 -> :accessor
;; 内部使用 -> アクセサなし

3. スロットの直接アクセスを避ける

;; Good - アクセサ経由
(user-name user)

;; Bad - 直接アクセス(テストやデバッグ以外)
(slot-value user 'name)