Common Lisp 物件系統（CLOS）是一種物件導向程式設計設施，它是 ANSI Common Lisp 的一部份。CLOS 是強力的動態物件系統，在根本上不同於靜態語言，比如 C++ 或 Java 中的那種 OOP 設施。CLOS 受到更早期的 Lisp 物件系統，比如 MIT Flavors 和 Xerox CommonLoops 的啟發，然而它比二者要更加泛化。



歷史

CLOS 最初被提議作為一種附加件，首次出現在 1988 年發表的《Common Lisp 物件導向程式設計》，和 1990 年出版的《Common Lisp 語言》第二版（也叫做 CLtL2）中。在 1994 年，CLOS 被接受為 ANSI 標準 Common Lisp 的一部份，並且已經被適配入其他 Lisp 方言比如 EuLisp 和 Emacs Lisp 之中。



特徵

CLOS 的基本建造塊是類、方法、泛化函式和類別的實例。CLOS 提供了定義它們的宏：`defclass`、`defmethod` 和 `defgeneric`。實例通過方法 `make-instance` 來建立。CLOS 不是基於原型語言，類必須聲明於物件可以實例化為這個類的成員之前。

類

類是槽的一個列表，它可以有多個超類，和一個特定的元類。槽（C++/Java 用語中的成員變數），可以由類（一個類的所有實例共享這個槽）或實例來分配。每個槽都有一個名字，而一個槽的值可以使用函式 `slot-value`，通過這個名字來存取。可以定義額外的特定泛化函式，來寫或讀這些槽的值。在 CLOS 類中的每個槽，都必須有一個唯一的名字。

如同多數動態語言中的 OO 系統那樣，CLOS 不強制封裝。任何槽都可以使用 `slot-value` 函式，或通過（可選的自動生成的）存取子方法來存取。要通過 `slot-value` 進行存取，就要知道這個槽的名字。CL 編程者使用這個語言的包設施，來聲明哪些函式或資料結構意圖被匯出。

CLOS 允許多重繼承。在多重繼承中方法執行的預設次序不正確的時候，編程者可以通過指定方法組合的次序，來解決這種菱形繼承問題（類 D 同時繼承一個超類 A 的兩個子類 B 和 C，四者形成菱形，如果 A 的某一方法被 B 和 C 覆寫，D 該繼承二者中哪一個？）。在 CLOS 中已經解決了圓–橢圓問題（圓是橢圓的長軸與短軸相等的特殊情況，故而是其子類，但圓不能繼承橢圓的使得其不再為圓的方法，比如單獨改變長軸或短軸）。而多數 OOP 設計模式，要麼消失，要麼在性質上更加簡單了。

CLOS 是動態的，意味著不只是內容，它的物件的「結構」，也可以在執行時間修改。CLOS 支援現場（on-the-fly）變更類別定義，即使正在考慮的這個類別的實例已經存在；還有通過 `change-class` 算子，變更一個給定實例的類別成員關係。CLOS 還允許在執行時間增加、重新定義和移除方法。

多分派

CLOS 是一個多分派系統，這意味著方法，可以依據它們所要求的任何或所有實際參數來指定。多數 OO 語言是單分派的，意味著方法只能依據第一個實際參數來指定。其他不常見特徵是方法不「屬於」類；類不為泛化函式或方法提供命名空間。方法是獨立於類而定義的，並且它們對類的槽沒有特殊的存取（比如 `this`、`self` 或 `protected`）。

在 CLOS 中的方法被組織入泛化函式。泛化函式是像函式一樣可呼叫的一個物件，它關聯著有共享的名字和參數結構的方法的一個搜集，其中每個都特定於不同的實際參數。因為 Common Lisp 為結構和內建資料類型（數值、字串、字元、符號等）提供了非 CLOS 類，CLOS 分派也工作在這些非 CLOS 類之上。CLOS 還支援分派在個體物件之上（eql 特殊化者）。CLOS 預設的不支援分派於所有 Common Lisp 資料類型上，比如分派不工作於完全特殊化的陣列類型，或通過 `deftype` 介入的類型。然而多數 Common Lisp 實現，提供了元物件協定，它允許泛化函式提供特定於應用的特殊化和分派規則。例如採用 SBCL 演示的下述代碼：

方法組合

在 CLOS 中的分派還不同於多數 OO 語言：

1. 給出一個實際參數列，確定一個可應用的方法的列表。
2. 這個列表依據它們的形式參數的特殊化者（specializer）的特殊性（specificity）來排序。
3. 接著使用泛化函式所用的那個方法組合，將從這個列表選擇出的那些方法組合成一個有效方法。
4. 接著用最初的實際參數呼叫這個有效方法。

這個分派機制工作在執行時間。增加或移除方法，將導致在執行時間變更有效方法（即使在以相同實際參數呼叫泛化函式的時候）。變更方法組合還導致不同的有效方法。

除了常規（「主要」）方法之外，還有 `:before`、`:after` 和 `:around` 這些「輔助」方法。前兩個方法按照類別為基層級的特定次序，分別先於或後於主要方法而呼叫。`:around` 方法可能控制主要方法是否執行。此外，編程者可以指定沿著類層級的所有可能的主要方法，是都應當被呼叫，還是只呼叫提供最接近匹配的那個方法。

「標準方法組合」提供上述的主要、之前、之後和圍繞方法。還有具有其他方法類型的其他方法組合。可以定義新的（簡單和複雜二者）方法組合和方法類型。



元物件協定

在 ANSI Common Lisp 標準之外，有一個廣泛實現的對 CLOS 的擴充，叫做元物件協定（MOP）。MOP 定義到 CLOS 實現基礎支撐的標準介面，將類、槽描述、泛化函式和方法自身，當作元類的實例，並允許定義新的元類，和修改所有 CLOS 行為。CLOS MOP 的靈活性，預示了面向切面編程，它是由同一群工程師比如 Gregor Kiczales 開發的。MOP 通過一組協定，定義了整個物件系統的行為。這些定義是依據 CLOS 定義的。因此有可能通過擴充或變更已提供的 CLOS 系統的功能，來建立新的物件系統。1991 年出版的圖書《元物件協定的藝術》描述了 CLOS MOP 的使用和實現。

各種 Common Lisp 實現對元物件協定有稍微不同的支援。Closer 計劃致力於提供缺失的特徵。



來自更早的基於 Lisp 的物件系統的影響

Flavor（和它的後繼者 New Flavors），是 MIT Lisp 機器上的物件系統。Lisp 機器作業系統的很大部份和它的很多應用，使用了 Flavors 或 New Flavors。Flavors 介入了多重繼承和 mixin 和其他一些特徵。Flavors 幾乎廢止了，儘管存在針對 Common Lisp 實現。Flavors 使用訊息傳遞範式。New Flavors 介入了泛化函式。

CommonLoops，是 Xerox Interlisp-D 的 LOOPS 的後繼者。CommonLoops 是針對 Common Lisp 的實現。叫做可移植 CommonLoops（PCL）的可移植實現，是第一個 CLOS 實現。PCL 被廣泛的移植了，並仍為很多 Common Lisp 實現提供 CLOS 實現的基礎。PCL 絕大部份以可移植的 Common Lisp 實現，而只有很少的系統依賴部份。



其他語言中的 CLOS

由於 CLOS 的能力和表達力，還有歷史上能獲得到 TinyCLOS，它是 Gregor Kiczales 為用於 Scheme 而書寫的簡化的可移植的 CLOS 實現，故而類 CLOS 的基於 MOP 的物件系統，成為大多數 Lisp 方言實現的事實規範，還能在一些其他語言的 OOP 設施中找到它：



參照



延伸閱讀


* Jim Veitch. A History and Description of CLOS. Peter H. Salus (編). Handbook of Programming Languages, Volume IV: Functional and Logic Programming Languages. Macmillan Technical Publishing. 1998 (1st edition): 107–158. ISBN 1-57870-011-6.



參考文獻


* Sonya Keene. Object-Oriented Programming in Common Lisp: A Programmer's Guide to CLOS (PDF). Addison-Wesley. 1988 [2022-02-05]. ISBN0-201-17589-4. （原始內容 (PDF) 存檔於 2022-05-06）.

* Gregor Kiczales, Jim des Rivieres, Daniel G. Bobrow. The Art of the Metaobject Protocol (PDF). MIT Press. 1991 [2022-02-05]. ISBN0-262-61074-4. （原始內容 (PDF) 存檔於 2022-02-05）.

* Jo A. Lawless and Molly M. Miller, Understanding CLOS: the Common Lisp Object System, 1991, Digital Press, ISBN 1-55558-064-5

* Andreas Paepcke. Object-Oriented Programming: the CLOS Perspective. The MIT Press. 1993 [2022-02-05]. ISBN0-262-16136-2. （原始內容存檔於 2022-02-05）.

* The Common Lisp Object System: An Overview （頁面存檔備份，存於網際網路檔案館） by Richard P. Gabriel and Linda DeMichiel provides a good introduction to the motivation for defining classes by means of generic functions.

* Fundamentals of CLOS （頁面存檔備份，存於網際網路檔案館） by Nick Levine provides a step-by-step exposure to the implementation of OO concepts in CLOS, and how to utilize them. It is intended for anybody with a basic knowledge of Lisp or Scheme.

* Common Lisp HyperSpec, Chapter 7: Objects （頁面存檔備份，存於網際網路檔案館）