混合与继承


Answers:


66

mixin通常与多重继承一起使用。因此,从这个意义上讲,没有任何区别。

细节是,mixin很少用作独立对象。

例如,假设您有一个名为“ ColorAndDimension”的混合,它添加了color属性以及width和height。

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

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


编辑-只是为了澄清。

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


29

mixin和继承之间有什么区别?

一个混合式是一个基类,你可以继承,以提供额外的功能。伪代码示例:

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

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

>>> obj = Mixin()

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

因此,mixin是继承的子集或特殊情况。

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

我个人发现在单个继承中使用混合是必要的,因为我们正在对很多相似的代码进行单元测试,但是测试用例是根据它们对基本用例的继承实例化的,并且是保持代码紧密的唯一方法一手(在同一模块中)在不影响覆盖范围的情况下,是从对象继承的,子案例从通用测试用例库和仅适用于它们的自定义库继承。

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

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

一个混入提供的功能,但无法直接使用它。用户打算通过(子)类使用它。

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

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

在这里,您无法实例化此对象,因为它需要一个子类才能使用具体方法来实现功能(尽管您可以从中访问该功能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模块中的某些类是父类的示例,它们均通过继承和必须由子类实现的抽象接口提供功能。这些想法不是相互排斥的。

摘要

简而言之,混入只是您自己不会实例化的基类,通常在多重继承中用作辅助基类。


18

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


7

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

这是维基百科的定义。

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

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

从实现的角度来看,您可以将其视为实现的接口。例如,如果Java支持多重继承,则Java中的抽象类可以被视为mixin。


我很难理解粗体的句子。听起来像“与A的(B?)的区别在于它(B?)确实需要A中的东西”。您是在谈论差异还是相似?
RayLuo

@RayLuo糟糕...我打错了字。抱歉使您困惑。混合视频不需要具有“是”关系
Alex

3

“从某种意义上说,mixin是一类的片段,它打算与其他类或mixin组成。” -DDJ

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

这是一篇很棒的DDJ文章,介绍了该主题。

Half-Life 2 /“ Source” SDK是C ++ mixins的一个很好的例子。在这种环境下,宏定义了可扩展的代码块,可以添加这些代码块以为类提供特定的“风味”或功能。

看一下Source Wiki示例:Authoring a Logical Entity。在示例代码中,DECLARE_CLASS宏可以被视为混合。Source SDK广泛使用mixin来标准化数据访问代码并将行为归于实体。


0

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

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

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

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


1
不确定您的第一个语句的正确性-类可以定义自己的方法
EugeneMi

0

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

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

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

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();

我知道这是一个荒谬的例子,但是,它可以使您理解...


0

tl; dr

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

但是无论如何,合成比IMO更好

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.