Mixin против наследования

Ответы:

67

Примесь обычно используется с множественным наследованием. Так что в этом смысле «никакой разницы».

Деталь в том, что миксин редко бывает полезен как отдельный объект.

Например, предположим, что у вас есть миксин с именем «ColorAndDimension», который добавляет свойство цвета, а также ширину и высоту.

Теперь вы можете добавить ColorAndDimension, скажем, в класс Shape, класс Sprite, класс Car и т. Д. И все они будут иметь одинаковый интерфейс (скажем, get / setColor, get / setHeight / Width и т. Д.)

Итак, в общем случае примесь является наследованием IS. Но вы можете утверждать, что это вопрос роли класса в общем домене относительно того, является ли миксин "основным" классом или просто миксином.


Редактировать - просто для уточнения.

Да, миксин на современном современном жаргоне можно рассматривать как интерфейс со связанной реализацией. На самом деле это обычное, старое, повседневное множественное наследование с использованием простого, старого, повседневного класса. Это просто конкретное приложение MI. Большинство языков не придают миксинам особого статуса; это просто класс, который был разработан для «смешивания», а не для использования отдельно.

Уилл Хартунг
источник
30

В чем разница между миксином и наследованием?

Смесь в базовый класс вы можете наследовать от предоставления дополнительной функциональности. Пример псевдокода:

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

Название «mix-in» указывает, что оно предназначено для смешивания с другим кодом. Таким образом, подразумевается, что вы не будете создавать экземпляр класса подмешивания самостоятельно. Следующий объект не имеет данных, и нет смысла создавать его экземпляр для вызова complex_method. (В этом случае вы можете просто определить функцию вместо класса.)

>>> obj = Mixin()

Часто смесь используется с другими базовыми классами.

Следовательно, миксины - это подмножество или особый случай наследования.

Преимущество смешанного наследования перед одиночным наследованием состоит в том, что вы можете написать код для функциональности один раз, а затем использовать ту же функциональность в нескольких разных классах. Недостатком является то, что вам может потребоваться поискать эту функциональность в других местах, а не там, где она используется, поэтому хорошо смягчить этот недостаток, оставив ее поблизости.

Я лично нашел смесь, необходимую для использования при одиночном наследовании, где мы тестируем много аналогичного кода, но тестовые примеры создаются на основе их наследования базового случая, и это единственный способ сохранить код близко к hand (и в том же модуле), не вмешиваясь в числа покрытия, должен наследовать от объекта, а дочерние кейсы наследуются как от универсальной базы тестовых примеров, так и от настраиваемой базы, которая применяется только к ним.

Смеси в сравнении и контрасте с абстрактными базовыми классами

Оба являются формой родительского класса, который не предназначен для создания экземпляров.

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модуле являются примерами родительских классов, которые обеспечивают функциональность через наследование и абстрактные интерфейсы, которые должны быть реализованы подклассом. Эти идеи не исключают друг друга.

Резюме

Проще говоря, подмешивание - это просто базовый класс, который вы не создадите самостоятельно, и обычно используется как вторичный базовый класс при множественном наследовании.

Аарон Холл
источник
18

подмешивание - это конкретный, ограниченный случай (множественного) наследования, используемый для целей реализации; некоторые языки (например, Ruby) поддерживают его без поддержки обобщенного множественного наследования.

Алекс Мартелли
источник
7

Mixin - это абстрактное понятие, и все, что соответствует его требованиям, можно рассматривать как миксин.

Вот определение из Википедии.

В объектно-ориентированных языках программирования миксин - это класс, который содержит методы для использования другими классами, не являясь родительским классом этих других классов. Как эти другие классы получают доступ к методам миксина, зависит от языка. Миксины иногда описываются как «включенные», а не «унаследованные».

Короче говоря, ключевое отличие от наследования состоит в том, что примешивание НЕ обязательно должно иметь отношение «есть», как в наследовании.

С точки зрения реализации вы можете рассматривать его как интерфейс с реализациями. Например, абстрактный класс в Java можно рассматривать как миксин, если Java поддерживает множественное наследование.

Alex
источник
Мне трудно понять смелое предложение. Это звучит как «разница (B?) От A в том, что для него (B?) Нужно что-то вроде A». Вы говорите о различии или сходстве?
RayLuo
@RayLuo Упс ... Я допустил опечатку. Извините, что сбил вас с толку. Вмешательства НЕ обязательно должны иметь отношения «есть»
Алекс
3

«Примесь - это фрагмент класса в том смысле, что он предназначен для создания с другими классами или миксинами». -DDJ

Примесь - это класс или фрагмент кода, который не предназначен для автономного использования, но вместо этого вы должны использовать его внутри другого класса. Либо составьте его как поле / переменную члена, либо как сегмент кода. Я больше всего знаком с последним. Это немного лучше, чем копирование и вставка шаблонного кода.

Вот отличная статья DDJ, которая знакомит с этой темой.

Half-Life 2 / "Source" SDK - отличный пример миксинов C ++. В этой среде макросы определяют значительные блоки кода, которые могут быть добавлены, чтобы придать классу особый «вкус» или функцию.

Взгляните на пример исходной вики: Создание логической сущности . В примере кода макрос DECLARE_CLASS можно рассматривать как миксин. Source SDK широко использует миксины для стандартизации кода доступа к данным и описания поведения сущностей.

Карл язычник
источник
0

При множественном наследовании новый класс может состоять из нескольких суперклассов. Вы можете вызывать только методы, определенные в любом из суперклассов.

С другой стороны, mixin - это абстрактный подкласс, который можно использовать для специализации поведения множества родительских классов. Миксины могут вызывать метод (например sayHello(): String), даже если они не определяют такой метод.

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

Как видите, вы можете позвонить, sayHello()даже если это нигде не определено. Если вы добавите миксин Mв класс C, он Cдолжен предоставить sayHello()метод.

jk_
источник
1
не уверен в правильности вашего первого утверждения - классы могут определять свои собственные методы
EugeneMi
0

Думаю, важно отметить, что миксин не подразумевает наследования . Согласно Википедии, Mixin - это:

В объектно-ориентированных языках программирования миксин - это класс, который содержит методы для использования другими классами, не являясь родительским классом этих других классов. Как эти другие классы получают доступ к методам миксина, зависит от языка. Миксины иногда описываются как «включенные», а не «унаследованные».

В частности, в таком языке, как perl, миксины можно добавлять с помощью модуля Exporter:

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

примесь и множественное наследование имеют одинаковую форму. Но имеют разную семантику: в миксине базовые классы обеспечивают реализацию функции. Для наследования базовые классы предоставляют интерфейс, а подкласс имеет реализацию.

Но в любом случае композиция предпочтительнее миксина. IMO

дель Бао
источник