Mixin

本頁使用了標題或全文手工轉換
維基百科,自由的百科全書

Mixin物件導向程式語言中的,提供了方法的實現。其他類可以訪問mixin類的方法而不必成為其子類。[1]Mixin有時被稱作"included"而不是"inherited"。mixin為使用它的class提供額外的功能,但自身卻不單獨使用(不能單獨生成實例對象,屬於抽象類)。因為有以上限制,Mixin類通常作為功能模組使用,在需要該功能時「混入」,而且不會使類的關係變得複雜。用戶與Mixin不是「is-a」的關係,而是「-able」關係

Mixin有利於代碼復用[2]又避免了多繼承的複雜。[3][4]使用Mixin享有單一繼承的單純性和多重繼承的共有性。介面與mixin相同的地方是都可以多繼承,不同的地方在於mixin是帶實現的。Mixin也可以看作是帶實現的interface英語Interface (object-oriented programming)。這種設計模式實現了依賴反轉原則[5]

歷史

Mixin最初出現在Symbolics.com的物件導向Flavors英語Flavors (programming language)系統(由Howard Cannon開發),使用了Lisp Machine Lisp英語Lisp Machine Lisp的物件導向方法。名稱起源於馬薩諸塞州薩默維爾Steve's Ice Cream英語Steve's Ice Cream[6] 這家雪糕店提供基本口味的雪糕(香草、巧克力等),混合入其他額外成分(堅果、曲奇、乳脂軟糖等)並稱這些為"mix-in",還註冊了商標。[7]

實現

程式語言支援

除了Flavors與CLOS (作為Common Lisp的部分),其他語言的支援:

一些語言允許執行時從一個對象拷貝方法到另一個對象。這可以「借」mixin的方法。

C#Visual Basic.NET支援介面的擴充方法(extension method)。

例子

Common Lisp

Python

Python中,除了使用protocol以外,也可以用多繼承的形式來實現Mixin。

  • 首先它必須表示某一種功能,而不是某個物品。Mixin必須責任單一,如果有多個功能,那就寫多個Mixin類。
  • Mixin不依賴於子類的實現
  • 子類即便沒有繼承這個Mixin類,也照樣可以工作,只是缺少了某個功能
  • 多重繼承時候,Mixin類應該在基本的父類別之前(即左側)
  • 為了區分普通的多繼承,mixin類的類名一般都會帶上字尾:Mixin、able、ible等。比如Python 2中的類UserDict.DictMixinDictMixin類包括部分實現,用戶的類只要實現幾個必須的函數介面,如:__getitem__(), __setitem__(), __delitem__(), keys()[12]

Python的SocketServer模組[13]提供了UDPServer類與TCPServer類,作為UDPTCPsocket伺服器。有兩個mixin類:ForkingMixInThreadingMixIn。通過如以下代碼的方式使用ThreadingMixIn擴充TCPServer

class ThreadingTCPServer(ThreadingMixIn, TCPServer):
  pass

ThreadingMixIn類為TCP伺服器添加了新功能,使每個新連接都會建立出新線程。而如果是ForkingMixIn,則會使每個新連接fork出新的行程。

Ruby

在ruby中,並不直接使用Mixin這個單詞,而是使用在類的聲明中include一個module的辦法。

JavaScript

在JavaScript中,Mixin可以用Object.assign(MyClass.prototype, MixinClass);實現。Mixin可以有自己的父類別。

對象-文字與extend方法

技術上可以通過繫結函數到對象的鍵,來給對象增加行為。但這導致在狀態與行為之間缺少分離等缺點:

  1. 它擾亂了模型域屬性與實現域屬性;
  2. 共同的行為沒有共用。元對象解決此問題通過分離對象的域相關屬性與行為相關的屬性。[14]

一個擴充函數(來自Underscore.js庫,把源對象的所有功能複製到目標對象, 特性, 函數等)用於混合行為:[15]

// This example may be contrived.
// It's an attempt to clean up the previous, broken example.
var Halfling = function (fName, lName) {
    this.firstName = fName;
    this.lastName = lName;
}

var NameMixin = {
    fullName: function () {
        return this.firstName + ' ' + this.lastName;
    },
    rename: function(first, last) {
        this.firstName = first;
        this.lastName = last;
        return this;
    }
};

var sam = new Halfling('Sam', 'Lowry');
var frodo = new Halfling('Freeda', 'Baggs');

// Mixin the other methods
_.extend(Halfling.prototype, NameMixin);

// Now the Halfling objects have access to the NameMixin methods
sam.rename('Samwise', 'Gamgee');
frodo.rename('Frodo', 'Baggins');

基於飛行Mixin方法的純函數與委託

上述描述方法得到廣泛使用。但下述方法更接近於JavaScript語言的基礎核心 - Delegation.

兩個基於模式的函數對象不需要extend的第三方實現就可完成這種技巧。

// Implementation
var EnumerableFirstLast = (function () { // function based module pattern.
    var first = function () {
        return this[0];
    },
    last = function () {
        return this[this.length - 1];
    };
    return function () {      // function based Flight-Mixin mechanics ...
        this.first  = first;  // ... referring to ...
        this.last   = last;   // ... shared code.
    };
}());

// Application - explicit delegation:
// applying [first] and [last] enumerable behavior onto [Array]'s [prototype].
EnumerableFirstLast.call(Array.prototype);

// Now you can do:
a = [1, 2, 3];
a.first(); // 1
a.last();  // 3

其他語言

介面與trait

參見

參考文獻

  1. ^ 存档副本. [2017-11-22]. (原始內容存檔於2005-02-07). 
  2. ^ 存档副本. [2017-11-22]. (原始內容存檔於2018-01-28). 
  3. ^ 存档副本. [2017-11-22]. (原始內容存檔於2018-04-15). 
  4. ^ Boyland, John; Giuseppe Castagna. Type-Safe Compilation of Covariant Specialization: A Practical Case. Pierre Cointe (編). ECOOP '96, Object-oriented Programming: 10th European Conference. Springer. 26 June 1996: 16–17 [17 January 2014]. ISBN 9783540614395. (原始內容存檔於2020-06-13). 
  5. ^ 存档副本. [2017-11-22]. (原始內容存檔於2015-09-25). 
  6. ^ Using Mix-ins with Python. [2017-11-22]. (原始內容存檔於2019-08-13). 
  7. ^ Mix-Ins (Steve's ice cream, Boston, 1975). [2017-11-22]. (原始內容存檔於2007-10-26). 
  8. ^ OOPSLA '90, Mixin based inheritance (pdf) (PDF). [2017-11-22]. (原始內容存檔 (PDF)於2019-02-14). 
  9. ^ slava. Factor/Features/The language. concatenative.org. 2010-01-25 [2012-05-15]. (原始內容存檔於2012-01-19). Factor's main language features: … Object system with Inheritance, Generic functions, Predicate dispatch and Mixins 
  10. ^ Mixin Class Composition. École polytechnique fédérale de Lausanne. [16 May 2014]. (原始內容存檔於2019-07-26). 
  11. ^ Mixin classes in XOTcl. [2017-11-22]. (原始內容存檔於2019-01-02). 
  12. ^ 3.7 UserDict -- Class wrapper for dictionary objects. [2019-02-02]. (原始內容存檔於2019-02-02). 
  13. ^ Source code for SocketServer in CPython 3.5. [2017-11-22]. (原始內容存檔於2015-10-24). 
  14. ^ 存档副本. [2017-11-22]. (原始內容存檔於2019-10-21). 
  15. ^ 存档副本. [2017-11-22]. (原始內容存檔於2015-09-21). 
  16. ^ 存档副本. [2017-11-22]. (原始內容存檔於2019-10-19). 
  17. ^ Implementing Mix-ins with C# Extension Methods. [2017-11-22]. (原始內容存檔於2017-07-09). 
  18. ^ I know the answer (it's 42) : Mix-ins and C#. [2017-11-22]. (原始內容存檔於2009-12-15). 
  19. ^ Mixins, generics and extension methods in C#. [2017-11-22]. (原始內容存檔於2018-03-03). 
  20. ^ The many talents of JavaScript for generalizing Role Oriented Programming approaches like Traits and Mixins頁面存檔備份,存於互聯網檔案館), April 11, 2014.
  21. ^ Angus Croll, A fresh look at JavaScript Mixins頁面存檔備份,存於互聯網檔案館), published May 31, 2011.
  22. ^ JavaScript Code Reuse Patterns頁面存檔備份,存於互聯網檔案館), April 19, 2013.
  23. ^ 存档副本. [2017-11-22]. (原始內容存檔於2017-07-27). 

外部連結