【发布时间】:2016-04-30 22:58:39
【问题描述】:
mixin 和继承有什么区别?
【问题讨论】:
标签: oop inheritance mixins
mixin 和继承有什么区别?
【问题讨论】:
标签: oop inheritance mixins
mix-in 是一种特定的、受限的(多重)继承,用于实现目的;一些语言(例如 Ruby)支持它,但不支持广义多重继承。
【讨论】:
mixin 通常与多重继承一起使用。所以,从这个意义上说,“没有区别”。
细节是 mixin 作为独立对象很少有用。
例如,假设您有一个名为“ColorAndDimension”的 mixin,它添加了一个颜色属性以及宽度和高度。
现在,您可以将 ColorAndDimension 添加到例如 Shape 类、Sprite 类、Car 类等。它们都将具有相同的接口(例如 get/setColor、get/setHeight/Width 等)
因此,在一般情况下,mixin 是继承。但是您可以争辩说,混入是“主要”类还是仅仅是混入,这取决于类在整个域中的角色。
编辑——只是为了澄清。
是的,在当今的现代术语中,可以将 mixin 视为具有相关实现的接口。它实际上只是使用普通的、旧的、日常的类的普通的、旧的、日常的多重继承。它恰好是 MI 的特定应用。大多数语言不给 mixin 任何特殊的地位。它只是一个旨在“混入”而不是独立使用的类。
【讨论】:
“从某种意义上说,mixin 是一个类的片段,它旨在与其他类或 mixin 组合在一起。” -DDJ
mixin 是一个类或代码片段,不能单独使用,而是应该在另一个类中使用它。将其组合为成员字段/变量或代码段。我对后者的接触最多。这比复制粘贴样板代码要好一点。
Here's a great DDJ article that introduces the subject.
Half-Life 2 / “Source” SDK 是 C++ mixin 的一个很好的例子。在那种环境中,宏定义了相当大的代码块,可以添加这些代码块以赋予类特定的“风味”或特性。
查看源维基示例:Authoring a Logical Entity。在示例代码中,可以将 DECLARE_CLASS 宏视为一个 mixin。 Source SDK 广泛使用 mixin 来标准化数据访问代码并将行为归因于实体。
【讨论】:
使用多重继承,新类可以由多个超类组成。您只能调用任何超类中定义的方法。
另一方面,mixin 是一个抽象子类,可以用来专门化各种父类的行为。 Mixins 可以调用一个方法(例如sayHello(): String),即使它们没有定义这样的方法。
mixin M {
name: String
defmethod greetings() { print sayHello() + " " + name}
}
如您所见,您可以调用sayHello(),即使它没有在任何地方定义。如果将 mixin M 添加到 C 类中,C 应该提供 sayHello() 方法。
【讨论】:
mixin 和继承有什么区别?
mix-in 是一个基类,您可以从中继承以提供额外的功能。伪代码示例:
class Mixin:
def complex_method(self):
return complex_functionality(self)
名称“mix-in”表示它旨在与其他代码混合。因此,推断是您不会自行实例化混合类。下面的对象没有数据,实例化它调用complex_method是没有意义的。 (在这种情况下,你也可以只定义一个函数而不是一个类。)
>>> obj = Mixin()
混入经常与其他基类一起使用。
因此,mixin 是继承的子集或特殊情况。
与单一继承相比,使用混入的优点是您可以一次性为功能编写代码,然后在多个不同的类中使用相同的功能。缺点是您可能需要在使用该功能的其他地方寻找该功能,因此最好通过将其放在附近来减轻该缺点。
我个人发现在单继承上使用混合是必要的,我们正在对许多类似的代码进行单元测试,但是测试用例是基于它们对基本用例的继承进行实例化的,这是保持手头上的代码(并且在同一个模块中),不会弄乱覆盖率,是从对象继承,并让子用例从通用测试用例库和仅适用于它们的自定义库继承。
两者都是不打算实例化的父类的一种形式。
mixin 提供功能,但无法直接使用。用户打算通过(子)类使用它。
抽象基类提供了一个接口,但没有可用的功能。用户旨在创建接口调用的功能。
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 模块中的一些类是父类的示例,它们都通过继承和抽象接口提供功能,必须由子类实现。这些想法并不相互排斥。
简单地说,mix-in 只是一个基类,您不会自行实例化它,通常用作多重继承中的辅助基类。
【讨论】:
我认为需要注意的是,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();
我知道这是一个荒谬的例子,但是,它说明了重点......
【讨论】:
mixin 是一个抽象的概念,任何符合其要求的东西都可以被认为是 mixin。
这是来自维基百科的定义。
在面向对象的编程语言中,mixin 是一个包含供其他类使用的方法的类,而不必是这些其他类的父类。这些其他类如何访问 mixin 的方法取决于语言。 Mixin 有时被描述为“包含”而不是“继承”。
简而言之,与继承的主要区别在于,mix-ins 不需要像继承那样具有“is-a”关系。
从实现的角度来看,你可以把它看成一个带有实现的接口。例如,如果 Java 支持多重继承,Java 中的抽象类可以被认为是 mixin。
【讨论】:
tl;博士
mixin 和多重继承具有相同的形式。但有不同的语义:mixin 有基础类提供函数实现。对于继承,基类提供接口,子类提供实现。
但无论如何,组合比 mixin IMO 更受欢迎
【讨论】:
Mixins 以一种更像“插件”的方式广泛使用。
它们是相同的,但在不同的上下文中。通常,当我们谈论继承时,我们谈论的是 SINGLE 继承,而 mixin 是一种允许 MULTIPLE 继承的构造。
这是一种在 OOP 世界中极具争议的语言结构,因为:
但除此之外,它是一种用于各种语言和框架的强大构造,一些示例如下:
【讨论】: