Во-первых, вы должны заметить, что миксины существуют только в языках множественного наследования. Вы не можете сделать миксин в Java или C #.
По сути, миксин - это автономный базовый тип, который обеспечивает ограниченную функциональность и полиморфный резонанс для дочернего класса. Если вы думаете о C #, подумайте об интерфейсе, который вам не нужно реализовывать, потому что он уже реализован; вы просто наследуете его и извлекаете выгоду из его функциональности.
Миксины обычно узкие по объему и не предназначены для расширения.
[править - почему:]
Я полагаю, я должен ответить почему, так как вы спросили. Большим преимуществом является то, что вам не нужно делать это снова и снова. В C # самое большое место, где миксин мог бы извлечь выгоду, может быть из шаблона утилизации . Всякий раз, когда вы реализуете IDisposable, вы почти всегда хотите следовать одному и тому же шаблону, но в итоге вы пишете и переписываете один и тот же базовый код с небольшими изменениями. Если бы существовал расширяемый миксин Disposal, вы могли бы сэкономить много лишнего набора текста.
[править 2 - чтобы ответить на другие ваши вопросы]
Что отличает миксин от множественного наследования? Это просто вопрос семантики?
Да. Разница между миксином и стандартным множественным наследованием является лишь вопросом семантики; класс с множественным наследованием может использовать миксин как часть этого множественного наследования.
Смысл mixin состоит в том, чтобы создать тип, который можно «смешать» с любым другим типом посредством наследования, не затрагивая наследующий тип, и в то же время предлагать некоторые полезные функциональные возможности для этого типа.
Опять же, подумайте об интерфейсе, который уже реализован.
Лично я не использую миксины, так как я развиваюсь в основном на языке, который их не поддерживает, поэтому мне очень трудно придумать достойный пример, который просто поставит это «ахах!» момент для вас. Но я попробую еще раз. Я собираюсь использовать надуманный пример - большинство языков уже так или иначе предоставляют эту функцию - но, надеюсь, это объяснит, как миксины должны создаваться и использоваться. Поехали:
Предположим, у вас есть тип, который вы хотите иметь возможность сериализации в и из XML. Вы хотите, чтобы тип предоставил метод «ToXML», который возвращает строку, содержащую фрагмент XML со значениями данных типа, и «FromXML», который позволяет типу восстанавливать свои значения данных из фрагмента XML в строку. Опять же, это надуманный пример, поэтому, возможно, вы используете файловый поток или класс XML Writer из библиотеки времени выполнения вашего языка ... что угодно. Дело в том, что вы хотите сериализовать свой объект в XML и получить новый объект обратно из XML.
Другим важным моментом в этом примере является то, что вы хотите сделать это в общем виде. Вам не нужно реализовывать методы «ToXML» и «FromXML» для каждого типа, который вы хотите сериализовать, вам нужны некоторые общие средства, гарантирующие, что ваш тип будет делать это, и он просто работает. Вы хотите повторного использования кода.
Если ваш язык поддерживает это, вы можете создать миксин XmlSerializable, который сделает вашу работу за вас. Этот тип будет реализовывать методы ToXML и FromXML. Используя некоторый механизм, который не важен для примера, он мог бы собрать все необходимые данные из любого типа, с которым он смешан, для создания фрагмента XML, возвращаемого ToXML, и он был бы в равной степени способен восстанавливать эти данные, когда FromXML называется.
И это все. Чтобы использовать его, вы должны иметь любой тип, который нужно сериализовать, чтобы XML наследовал от XmlSerializable. Когда бы вам ни понадобилось сериализовать или десериализовать этот тип, вы просто вызывали бы ToXML или FromXML. Фактически, поскольку XmlSerializable является полноценным типом и полиморфным, вы могли бы создать сериализатор документов, который ничего не знает о вашем исходном типе, принимая только, скажем, массив типов XmlSerializable.
Теперь представьте, что вы можете использовать этот сценарий для других целей, например, для создания миксина, который гарантирует, что каждый класс, который смешивает его, регистрирует каждый вызов метода, или миксина, который обеспечивает транзакционность для типа, который его смешивает. Список можно продолжать и продолжать.
Если вы просто думаете о миксине как о небольшом базовом типе, предназначенном для добавления небольшого количества функциональности к типу, без какого-либо влияния на этот тип, то вы просто великолепны.
С надеждой. :)