mixin 和继承有什么区别?
9 回答
mixin 通常与多重继承一起使用。所以,从这个意义上说,“没有区别”。
细节是 mixin 作为一个独立的对象很少有用。
例如,假设您有一个名为“ColorAndDimension”的 mixin,它添加了一个颜色属性以及宽度和高度。
现在,您可以将 ColorAndDimension 添加到例如 Shape 类、Sprite 类、Car 类等。它们都将具有相同的接口(例如 get/setColor、get/setHeight/Width 等)
因此,在一般情况下,mixin 是继承。但是您可以争辩说,混入是“主要”类还是仅仅是混入,这取决于类在整个域中的作用。
编辑——只是为了澄清。
是的,在当今的现代术语中,可以认为 mixin 是具有相关实现的接口。它实际上只是使用普通的、旧的、日常的类的普通的、旧的、日常的多重继承。它恰好是 MI 的特定应用。大多数语言不给 mixin 任何特殊的地位。它只是一个旨在“混合”而不是独立使用的类。
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 只是一个基类,您不会自己实例化它,通常用作多重继承中的辅助基类。
混合是用于实现目的的(多重)继承的一种特定的、受限制的情况;某些语言(例如 Ruby)支持它,但不支持广义多重继承。
Mixin 是一个抽象的概念,任何符合其要求的东西都可以被认为是一个 mixin。
这是维基百科的定义。
在面向对象的编程语言中,mixin 是一个类,其中包含供其他类使用的方法,而不必是这些其他类的父类。这些其他类如何访问 mixin 的方法取决于语言。Mixin 有时被描述为“包含”而不是“继承”。
简而言之,与继承的主要区别在于混合不需要像继承那样具有“is-a”关系。
从实现的角度来看,你可以把它看成一个带有实现的接口。例如,如果 Java 支持多重继承,Java 中的抽象类可以被认为是 mixin。
“从某种意义上说,mixin 是一个类的一个片段,它旨在与其他类或 mixin 组合在一起。” -DDJ
mixin 是一个类或代码片段,它不适合独立使用,而是应该在另一个类中使用它。将其组合为成员字段/变量或代码段。我对后者的接触最多。它比复制粘贴样板代码好一点。
Half-Life 2 / “Source” SDK 是 C++ mixin 的一个很好的例子。在那种环境中,宏定义了相当大的代码块,可以添加这些代码块以赋予类特定的“风味”或特性。
查看源 wiki 示例:创作逻辑实体。在示例代码中,可以将 DECLARE_CLASS 宏视为一个 mixin。Source SDK 广泛使用 mixin 来标准化数据访问代码并将行为归因于实体。
Mixin 以一种更像“插件”的方式被广泛使用。
它们是相同的,但在不同的上下文中。通常当我们谈论继承时,我们谈论的是 SINGLE 继承,而 mixin 是一种允许 MULTIPLE 继承的构造。
这是一种在 OOP 世界中极具争议的语言结构,因为:
- 必须解决的歧义
- 很多时候“mixin”类不能单独工作,并且可能与其他 mixin 冲突
- 它可能导致“钻石继承问题”,两个超类可以从同一个类继承
但除此之外,它是一种用于各种语言和框架的强大构造,一些示例是:
- 姜戈
- 打字稿
通过多重继承,新类可以由多个超类组成。您只能调用任何超类中定义的方法。
另一方面,mixin 是一个抽象子类,可以用来专门化各种父类的行为。Mixins 可以调用一个方法(例如sayHello(): String
),即使它们没有定义这样的方法。
mixin M {
name: String
defmethod greetings() { print sayHello() + " " + name}
}
如您所见,sayHello()
即使它没有在任何地方定义,您也可以调用。如果将 mixin 添加M
到 class C
,则C
应该提供sayHello()
方法。
我认为需要注意的是,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();
我知道这是一个荒谬的例子,但是,它明白了……
tl;博士
mixin 和多重继承具有相同的形式。但有不同的语义:mixin 有基础类提供函数实现。对于继承,基类提供接口,子类提供实现。
但无论如何,组合比 mixin IMO 更受欢迎