Mixin

Mixin面向对象程序设计语言中的,提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类。[1]Mixin有时被称作"included"而不是"inherited"。mixin为使用它的class提供额外的功能,但自身却不单独使用(不能单独生成实例对象,属于抽象类)。因为有以上限制,Mixin类通常作为功能模块使用,在需要该功能时“混入”,而且不会使类的关系变得复杂。使用者与Mixin不是“is-a”的关系,而是「-able」关系

Mixin有利于代码复用[2]又避免了多继承的复杂。[3][4]使用Mixin享有单一继承的单纯性和多重继承的共有性。接口与mixin相同的地方是都可以多继承,不同的地方在于mixin是带实现的。Mixin也可以看作是带实现的interface。这种设计模式实现了依赖反转原则[5]

历史

Mixin最初出现在Symbolics.com的面向对象Flavors系统(由Howard Cannon开发),使用了Lisp Machine Lisp的面向对象方法。名称起源于马萨诸塞州萨默维尔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. . Pierre Cointe (编). . Springer. 26 June 1996: 16–17 [17 January 2014]. ISBN 9783540614395. (原始内容存档于2020-06-13).
  5. . [2017-11-22]. (原始内容存档于2015-09-25).
  6. . [2017-11-22]. (原始内容存档于2019-08-13).
  7. . [2017-11-22]. (原始内容存档于2007-10-26).
  8. (PDF). [2017-11-22]. (原始内容存档 (PDF)于2019-02-14).
  9. slava. . 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. . École polytechnique fédérale de Lausanne. [16 May 2014]. (原始内容存档于2019-07-26).
  11. . [2017-11-22]. (原始内容存档于2019-01-02).
  12. . [2019-02-02]. (原始内容存档于2019-02-02).
  13. . [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. . [2017-11-22]. (原始内容存档于2017-07-09).
  18. . [2017-11-22]. (原始内容存档于2009-12-15).
  19. . [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).

外部链接

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.