Mixin vs herencia

Respuestas:

66

Un mixin se usa típicamente con herencia múltiple. Entonces, en ese sentido, "no hay diferencia".

El detalle es que un mixin rara vez es útil como objeto independiente.

Por ejemplo, digamos que tiene un mixin llamado "ColorAndDimension", que agrega una propiedad de color y ancho y alto.

Ahora, puede agregar ColorAndDimension a, digamos, una clase Shape, una clase Sprite, una clase Car, etc. Y todas tendrán la misma interfaz (digamos get / setColor, get / setHeight / Width, etc.)

Entonces, en el caso genérico, una mezcla ES herencia. Pero se puede argumentar que es una cuestión del papel de la clase en el dominio general en cuanto a si un mixin es una clase "primaria" o simplemente un mixin.


Editar - solo para aclarar.

Sí, un mixin puede considerarse, en la jerga moderna actual, una interfaz con una implementación asociada. Realmente es una herencia múltiple simple, vieja y cotidiana usando una clase simple, vieja y cotidiana. Simplemente resulta ser una aplicación específica de MI. La mayoría de los idiomas no otorgan ningún estatus especial a las mezclas; es solo una clase que fue diseñada para ser "mezclada", en lugar de usarse de forma independiente.

Will Hartung
fuente
29

¿Cuál es la diferencia entre un mixin y una herencia?

Una combinación es una clase base de la que puede heredar para proporcionar funcionalidad adicional. Ejemplo de pseudocódigo:

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

El nombre "mix-in" indica que está destinado a mezclarse con otro código. Como tal, la inferencia es que no crearía una instancia de la clase mix-in por sí sola. El siguiente objeto no tiene datos y no tiene sentido crear una instancia para llamar a complex_method. (En ese caso, también puede definir una función en lugar de una clase).

>>> obj = Mixin()

Con frecuencia, la mezcla se usa con otras clases base.

Por lo tanto, los mixins son un subconjunto, o un caso especial, de herencia.

Las ventajas de usar una combinación sobre la herencia única son que puede escribir código para la funcionalidad una vez y luego usar la misma funcionalidad en varias clases diferentes. La desventaja es que es posible que deba buscar esa funcionalidad en otros lugares distintos de donde se usa, por lo que es bueno mitigar esa desventaja manteniéndola cerca.

Personalmente, he encontrado una combinación necesaria para usar sobre una herencia única donde estamos probando un montón de código similar, pero los casos de prueba se instancian en función de su herencia de un caso base, y la única forma de mantener el código cerca en hand (y en el mismo módulo), sin jugar con los números de cobertura, es heredar del objeto y hacer que los casos secundarios hereden tanto de la base de casos de prueba universal como de la base personalizada que solo se aplica a ellos.

Mixins en comparación y contraste con clases base abstractas

Ambos son una forma de clase principal que no está destinada a crear instancias.

Un mixin proporciona funcionalidad, pero no puede usarlo directamente. Se pretende que un usuario lo utilice a través de una (sub) clase.

Una clase base abstracta proporciona una interfaz, pero sin funcionalidad utilizable. Se pretende que un usuario cree la funcionalidad llamada por la interfaz.

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

Aquí se le impide crear instancias de este objeto porque requiere una subclase para implementar la funcionalidad con un método concreto (aunque puede acceder a la funcionalidad desde 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

En Python, algunas clases del abcmódulo son ejemplos de clases padre que proporcionan funcionalidad a través de la herencia y las interfaces abstractas que debe implementar la subclase. Estas ideas no son mutuamente excluyentes.

Resumen

En pocas palabras, una mezcla es solo una clase base que no crearía una instancia por sí sola y, por lo general, se usa como una clase base secundaria en herencia múltiple.

Aaron Hall
fuente
18

la mezcla es un caso específico y restringido de herencia (múltiple) que se utiliza con fines de implementación; algunos lenguajes (por ejemplo, Ruby) lo admiten sin admitir herencia múltiple generalizada.

Alex Martelli
fuente
7

Mixin es un concepto abstracto y cualquier cosa que cumpla con sus requisitos puede considerarse como mixin.

Aquí hay una definición de Wikipedia.

En los lenguajes de programación orientados a objetos, un mixin es una clase que contiene métodos para ser usados ​​por otras clases sin tener que ser la clase padre de esas otras clases. La forma en que esas otras clases acceden a los métodos del mixin depende del idioma. Los mixins a veces se describen como "incluidos" en lugar de "heredados".

En resumen, la diferencia clave con una herencia es que las mezclas NO necesitan tener una relación "es-a" como en la herencia.

Desde el punto de vista de la implementación, puede pensarlo como una interfaz con implementaciones. Por ejemplo, una clase abstracta en Java podría considerarse como una combinación si Java admitiera herencia múltiple.

Alex
fuente
Me está costando entender la frase en negrita. Suena como "la diferencia (de B?) De A es que (¿B?) Necesita algo como en A". ¿Estás hablando de diferencia o semejanza?
RayLuo
@RayLuo Vaya ... Cometí un error tipográfico. Perdon por confundirte. Los mix-ins NO necesitan tener una relación "es-un"
Alex
3

"Un mixin es un fragmento de una clase en el sentido de que está destinado a estar compuesto con otras clases o mixins". -DDJ

Un mixin es una clase o fragmento de código que no está destinado a un uso independiente, sino que se supone que debe usarlo dentro de otra clase. Ya sea componiéndolo como un campo miembro / variable o como un segmento de código. Tengo la mayor exposición a lo último. Es un poco mejor que copiar y pegar código estándar.

Aquí hay un gran artículo de DDJ que presenta el tema.

Half-Life 2 / "Source" SDK es un gran ejemplo de mixins de C ++. En ese entorno, las macros definen bloques de código considerables que se pueden agregar para darle a la clase un "sabor" o característica específica.

Mire el ejemplo de la wiki de origen: Creación de una entidad lógica . En el código de ejemplo, la macro DECLARE_CLASS puede considerarse una mezcla. Source SDK usa mixins ampliamente para estandarizar el código de acceso a datos y atribuir comportamientos a entidades.

Karl el pagano
fuente
0

Con herencia múltiple, la nueva clase puede estar compuesta de múltiples superclases. Solo puede llamar a métodos definidos en cualquiera de las superclases.

Por otro lado, mixin es una subclase abstracta que se puede utilizar para especializar el comportamiento de una variedad de clases principales. Los mixins pueden llamar a un método (por ejemplo sayHello(): String) aunque no definan dicho método.

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

Como puede ver, puede llamar sayHello()aunque no esté definido en ninguna parte. Si agrega el mixin Ma la clase C, Cdebe proporcionar el sayHello()método.

jk_
fuente
1
no estoy seguro de la exactitud de su primera declaración - las clases pueden definir sus propios métodos
EugeneMi
0

Creo que es importante tener en cuenta que el mixin no implica herencia . Según wikipedia, un Mixin es:

En los lenguajes de programación orientados a objetos, un mixin es una clase que contiene métodos para ser usados ​​por otras clases sin tener que ser la clase padre de esas otras clases. La forma en que esas otras clases acceden a los métodos del mixin depende del idioma. Los mixins a veces se describen como "incluidos" en lugar de "heredados".

Específicamente, en un lenguaje como perl, se pueden agregar mixins usando el módulo Exportador:

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'));
}

Que se puede mezclar en cualquier módulo que contenga uno o más métodos a la vez:

package MrT

use Mixins qw(pity);

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

sub _who_do_i_pity {
    return 'da foo!'
}

Luego, en su MrTmódulo se puede usar así:

use MrT;

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

Sé que es un ejemplo absurdo, pero transmite el mensaje ...

Lucas
fuente
0

tl; dr

mixin y herencia múltiple tienen la misma forma. Pero tienen una semántica diferente: mixin tiene las clases básicas que proporcionan la implementación de la función. Para la herencia, las clases base proporcionan la interfaz y la subclase tiene la implementación.

Pero de todos modos, la composición es preferible a la mezcla IMO.

del bao
fuente