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). 

外部链接 编辑