【问题标题】:Mixin vs inheritanceMixin vs inheritance
【发布时间】:2016-04-30 22:58:39
【问题描述】:

mixin 和继承有什么区别?

【问题讨论】:

标签: oop inheritance mixins


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

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

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

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


    编辑——只是为了澄清。

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

    【讨论】:

      【解决方案3】:

      “从某种意义上说,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 来标准化数据访问代码并将行为归因于实体。

      【讨论】:

        【解决方案4】:

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

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

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

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

        【讨论】:

        • 不确定您的第一条语句的正确性 - 类可以定义自己的方法
        【解决方案5】:

        mixin 和继承有什么区别?

        mix-in 是一个基类,您可以从中继承以提供额外的功能。伪代码示例:

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

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

        >>> obj = Mixin()
        

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

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

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

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

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

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

        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 只是一个基类,您不会自行实例化它,通常用作多重继承中的辅助基类。

        【讨论】:

          【解决方案6】:

          我认为需要注意的是,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();
          

          我知道这是一个荒谬的例子,但是,它说明了重点......

          【讨论】:

            【解决方案7】:

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

            这是来自维基百科的定义。

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

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

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

            【讨论】:

            • 我很难理解粗体字。听起来“(B?)与A的区别在于它(B?)确实需要A中的东西”。你说的是区别还是相似?
            • @RayLuo 哎呀...我打错了。很抱歉让您感到困惑。混音不需要有“is-a”关系
            • Java 通过在接口中提供默认方法来实现混入。这样,所有的类混入这个功能都会是一个实现的接口。这有点奇怪吗?
            【解决方案8】:

            tl;博士

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

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

            【讨论】:

              【解决方案9】:

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

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

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

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2022-12-27
                • 2012-09-21
                相关资源
                最近更新 更多