121

mixin 和继承有什么区别?

4

9 回答 9

80

mixin 通常与多重继承一起使用。所以,从这个意义上说,“没有区别”。

细节是 mixin 作为一个独立的对象很少有用。

例如,假设您有一个名为“ColorAndDimension”的 mixin,它添加了一个颜色属性以及宽度和高度。

现在,您可以将 ColorAndDimension 添加到例如 Shape 类、Sprite 类、Car 类等。它们都将具有相同的接口(例如 get/setColor、get/setHeight/Width 等)

因此,在一般情况下,mixin 是继承。但是您可以争辩说,混入是“主要”类还是仅仅是混入,这取决于类在整个域中的作用。


编辑——只是为了澄清。

是的,在当今的现代术语中,可以认为 mixin 是具有相关实现的接口。它实际上只是使用普通的、旧的、日常的类的普通的、旧的、日常的多重继承。它恰好是 MI 的特定应用。大多数语言不给 mixin 任何特殊的地位。它只是一个旨在“混合”而不是独立使用的类。

于 2009-05-13T20:42:20.790 回答
36

mixin 和继承有什么区别?

混入是一个基类,您可以从中继承以提供附加功能。伪代码示例:

class Mixin:
    def complex_method(self):
        return complex_functionality(self)

名称“mix-in”表示它旨在与其他代码混合。因此,推断是您不会自行实例化混合类。下面的对象没有数据,实例化它调用complex_method是没有意义的。(在这种情况下,您也可以只定义一个函数而不是一个类。)

>>> obj = Mixin()

混入经常与其他基类一起使用。

因此mixins 是继承的一个子集或特殊情况。

与单一继承相比,使用混合的优点是您可以为该功能编写一次代码,然后在多个不同的类中使用相同的功能。缺点是您可能需要在使用该功能的其他地方寻找该功能,因此最好通过将其放在附近来减轻该缺点。

我个人发现在单一继承上使用混合是必要的,我们正在对许多类似的代码进行单元测试,但是测试用例是基于它们对基本用例的继承来实例化的,并且是保持代码接近的唯一方法手(并且在同一个模块中),而不弄乱覆盖率,是从对象继承,并让子用例从通用测试用例库和仅适用于它们的自定义库继承。

Mixin 与抽象基类的比较和对比

两者都是不打算实例化的父类的一种形式。

mixin提供了功能,但不能直接使用它。用户打算通过(子)类使用它。

抽象基类提供接口,但没有可用的功能。用户旨在创建接口调用的功能。

class Abstraction(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def complex_method(self):
        return complex_functionality(self)

在这里,您无法实例化此对象,因为它需要一个子类来使用具体方法实现功能(尽管您可以访问 from 中的功能super()):

>>> obj = Abstraction()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Abstraction with
abstract methods complex_method

在 Python 中,abc模块中的某些类是父类的示例,它们都通过继承和抽象接口提供功能,必须由子类实现。这些想法并不相互排斥。

概括

简而言之,mix-in 只是一个基类,您不会自己实例化它,通常用作多重继承中的辅助基类。

于 2015-01-12T17:25:57.663 回答
19

混合是用于实现目的的(多重)继承的一种特定的、受限制的情况;某些语言(例如 Ruby)支持它,但不支持广义多重继承。

于 2009-05-13T20:36:59.440 回答
9

Mixin 是一个抽象的概念,任何符合其要求的东西都可以被认为是一个 mixin。

这是维基百科的定义。

在面向对象的编程语言中,mixin 是一个类,其中包含供其他类使用的方法,而不必是这些其他类的父类。这些其他类如何访问 mixin 的方法取决于语言。Mixin 有时被描述为“包含”而不是“继承”。

简而言之,与继承的主要区别在于混合不需要像继承那样具有“is-a”关系。

从实现的角度来看,你可以把它看成一个带有实现的接口。例如,如果 Java 支持多重继承,Java 中的抽象类可以被认为是 mixin。

于 2016-05-06T19:18:45.203 回答
3

“从某种意义上说,mixin 是一个类的一个片段,它旨在与其他类或 mixin 组合在一起。” -DDJ

mixin 是一个类或代码片段,它不适合独立使用,而是应该在另一个类中使用它。将其组合为成员字段/变量或代码段。我对后者的接触最多。它比复制粘贴样板代码好一点。

这是一篇介绍该主题的精彩 DDJ 文章。

Half-Life 2 / “Source” SDK 是 C++ mixin 的一个很好的例子。在那种环境中,宏定义了相当大的代码块,可以添加这些代码块以赋予类特定的“风味”或特性。

查看源 wiki 示例:创作逻辑实体。在示例代码中,可以将 DECLARE_CLASS 宏视为一个 mixin。Source SDK 广泛使用 mixin 来标准化数据访问代码并将行为归因于实体。

于 2009-05-13T20:52:58.417 回答
2

Mixin 以一种更像“插件”的方式被广泛使用。

它们是相同的,但在不同的上下文中。通常当我们谈论继承时,我们谈论的是 SINGLE 继承,而 mixin 是一种允许 MULTIPLE 继承的构造。

这是一种在 OOP 世界中极具争议的语言结构,因为:

  • 必须解决的歧义
  • 很多时候“mixin”类不能单独工作,并且可能与其他 mixin 冲突
  • 它可能导致“钻石继承问题”,两个超类可以从同一个类继承

但除此之外,它是一种用于各种语言和框架的强大构造,一些示例是:

于 2020-10-16T16:46:12.763 回答
0

通过多重继承,新类可以由多个超类组成。您只能调用任何超类中定义的方法。

另一方面,mixin 是一个抽象子类,可以用来专门化各种父类的行为。Mixins 可以调用一个方法(例如sayHello(): String),即使它们没有定义这样的方法。

mixin M {
    name: String
    defmethod greetings() { print sayHello() + " " + name}
}

如您所见,sayHello()即使它没有在任何地方定义,您也可以调用。如果将 mixin 添加M到 class C,则C应该提供sayHello()方法。

于 2011-01-26T09:19:43.383 回答
0

我认为需要注意的是,mixin并不意味着继承。根据维基百科,Mixin是:

在面向对象的编程语言中,mixin 是一个包含供其他类使用的方法的类,而不必是这些其他类的父类。这些其他类如何访问 mixin 的方法取决于语言。Mixin 有时被描述为“包含”而不是“继承”。

具体来说,在 perl 之类的语言中,可以使用 Exporter 模块添加 mixin:

package Mixins;

use Exporter qw(import);
our @EXPORT_OK = qw(pity);

# assumes it will be mixed-in to a class with a _who_do_i_pity method
sub pity {
    my ($self) = @_;
    printf("I pity %s\n", $self->_who_do_i_pity('da foo'));
}

可以将其混入一次包含一个或多个方法的任何模块中:

package MrT

use Mixins qw(pity);

sub new {
    return bless({}, shift);
}

sub _who_do_i_pity {
    return 'da foo!'
}

然后在您的MrT模块中可以这样使用:

use MrT;

MrT->new()->pity();

我知道这是一个荒谬的例子,但是,它明白了……

于 2016-04-15T16:37:16.727 回答
0

tl;博士

mixin 和多重继承具有相同的形式。但有不同的语义:mixin 有基础类提供函数实现。对于继承,基类提供接口,子类提供实现。

但无论如何,组合比 mixin IMO 更受欢迎

于 2017-03-26T06:07:29.713 回答