Что такое mixin и почему они полезны?

В " Программировании Python " Марк Лутц упоминает "миксины". Я из C/C++/С# фона, и я не слышал термин раньше. Что такое миксин?

Читая между строк этого примера (который я связал, потому что он довольно длинный), я предполагаю, что это случай использования множественного наследования для расширения класса, а не для "правильного" подкласса. Это правильно?

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

Что отличает миксин от множественного наследования? Это просто вопрос семантики?

Ответ 1

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

  1. Вы хотите предоставить множество дополнительных функций для класса.
  2. Вы хотите использовать одну конкретную функцию во множестве разных классов.

Например, номер один, рассмотрите систему запроса и ответа werkzeug. Я могу сделать простой старый объект запроса, сказав:

from werkzeug import BaseRequest

class Request(BaseRequest):
    pass

Если я хочу добавить поддержку заголовка Accept, я бы сделал это

from werkzeug import BaseRequest, AcceptMixin

class Request(AcceptMixin, BaseRequest):
    pass

Если бы я хотел создать объект запроса, поддерживающий прием заголовков, etags, проверку подлинности и поддержку пользовательского агента, я мог бы сделать это:

from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin

class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
    pass

Разница тонкая, но в приведенных выше примерах классы mixin не были созданы самостоятельно. В более традиционном множественном наследовании AuthenticationMixin (например), вероятно, будет чем-то более похожим на Authenticator. То есть, класс, вероятно, будет разработан для самостоятельной работы.

Ответ 2

Во-первых, вы должны заметить, что mixins существуют только в языках с несколькими наследованиями. Вы не можете использовать mixin в Java или С#.

В принципе, mixin является автономным базовым типом, который обеспечивает ограниченную функциональность и полиморфный резонанс для дочернего класса. Если вы думаете на С#, подумайте о интерфейсе, который вам не нужно реализовывать, поскольку он уже реализован; вы просто наследуете его и извлекаете выгоду из его функциональности.

Микшины, как правило, узкие по охвату и не предназначены для расширения.

[править] - почему:]

Полагаю, мне следует обратиться к тому, почему, поскольку вы спросили. Большим преимуществом является то, что вам не нужно делать это снова и снова. В С# наибольшее место, где мог бы быть использован миксин, можно найти в схеме удаления. Всякий раз, когда вы реализуете IDisposable, вы почти всегда хотите следовать одному и тому же шаблону, но в итоге вы записываете и переписываете один и тот же базовый код с небольшими вариациями. Если бы существовала расширяемая система Disposal mixin, вы могли бы сэкономить много лишнего набора текста.

[edit 2 - для ответа на другие вопросы]

Что отличает mixin от множественного наследования? Это просто вопрос семантики?

Да. Разница между mixin и стандартным множественным наследованием - это всего лишь вопрос семантики; класс, который имеет множественное наследование, может использовать mixin как часть этого множественного наследования.

Точкой mixin является создание типа, который может быть "смешанным" с любым другим типом через наследование, не затрагивая тип наследования, при этом предлагая некоторые полезные функции для этого типа.

Снова подумайте о интерфейсе, который уже реализован.

Я лично не использую mixins, так как я развиваюсь в основном на языке, который их не поддерживает, поэтому у меня очень трудное время придумать достойный пример, который будет просто поставлять это "аха!". момент для вас. Но я попробую еще раз. Я собираюсь использовать пример, который был изобретен - большинство языков уже каким-то образом предоставляют эту функцию, но это, надеюсь, объяснит, как должны создаваться и использоваться микшины. Здесь:

Предположим, что у вас есть тип, который вы хотите сериализовать в и из XML. Вы хотите, чтобы тип предоставлял метод "ToXML", который возвращает строку, содержащую фрагмент XML, с значениями данных этого типа и "FromXML", который позволяет типу восстанавливать свои значения данных из XML-фрагмента в строке. Опять же, это надуманный пример, поэтому, возможно, вы используете поток файлов или класс XML Writer из вашей библиотеки времени исполнения... что угодно. Дело в том, что вы хотите сериализовать свой объект в XML и вернуть новый объект из XML.

Другим важным моментом в этом примере является то, что вы хотите сделать это в общем виде. Вы не хотите внедрять метод "ToXML" и "FromXML" для каждого типа, который вы хотите сериализовать, вам нужны некоторые общие средства обеспечения того, чтобы ваш тип выполнял это, и он просто работает. Вы хотите повторное использование кода.

Если ваш язык поддерживает его, вы можете создать XmlSerializable mixin, чтобы выполнить свою работу за вас. Этот тип будет реализовывать методы ToXML и FromXML. При использовании некоторого механизма, не важного для примера, он мог бы собирать все необходимые данные из любого типа, с которым он смешивался, для создания XML-фрагмента, возвращаемого ToXML, и он также мог бы восстановить эти данные, когда FromXML называется.

И.. что это. Чтобы использовать его, у вас будет любой тип, который должен быть сериализован для XML, наследуемого от XmlSerializable. Всякий раз, когда вам нужно было сериализовать или десериализовать этот тип, вы просто вызываете ToXML или FromXML. На самом деле, поскольку XmlSerializable является полнофункциональным типом и полиморфным, вы могли бы создать сериализатор документов, который ничего не знает о вашем исходном типе, принимая только, скажем, массив XmlSerializable типов.

Теперь представьте, что вы используете этот сценарий для других вещей, например создание mixin, который гарантирует, что каждый класс, который смешивает его в журналах с каждым вызовом метода, или mixin, который обеспечивает транзакцию для типа, в котором он находится. Список может продолжаться и на.

Если вы просто думаете о том, что mixin является небольшим базовым типом, предназначенным для добавления небольшого количества функций к типу, не влияя на этот тип, тогда вы золотые.

Надеюсь.:)

Ответ 3

Цель этого ответа - объяснить миксины на примерах:

  • Автономный: короткий, без необходимости знать какие-либо библиотеки, чтобы понять пример.

  • в Python, а не в других языках.

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

Он также должен рассмотреть спорный вопрос:

Многократное наследование необходимо или нет, чтобы характеризовать миксин?

Определения

Я до сих пор не видел цитату из "авторитетного" источника, в которой четко сказано, что такое миксин в Python.

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

Консенсус может отличаться для разных языков.

Определение 1: нет множественного наследования

Mixin - это такой класс, что некоторый метод класса использует метод, который не определен в классе.

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

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

Классическим примером является реализация всех операторов сравнения только из <= и ==:

class ComparableMixin(object):
    """This class has methods which use '<=' and '==',
    but this class does NOT implement those methods."""
    def __ne__(self, other):
        return not (self == other)
    def __lt__(self, other):
        return self <= other and (self != other)
    def __gt__(self, other):
        return not self <= other
    def __ge__(self, other):
        return self == other or self > other

class Integer(ComparableMixin):
    def __init__(self, i):
        self.i = i
    def __le__(self, other):
        return self.i <= other.i
    def __eq__(self, other):
        return self.i == other.i

assert Integer(0) <  Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) >  Integer(0)
assert Integer(1) >= Integer(1)

# It is possible to instantiate a mixin:
o = ComparableMixin()
# but one of its methods raise an exception:
#o != o 

Этот конкретный пример мог быть реализован с помощью декоратора functools.total_ordering(), но игра здесь заключалась в том, чтобы заново изобрести колесо:

import functools

@functools.total_ordering
class Integer(object):
    def __init__(self, i):
        self.i = i
    def __le__(self, other):
        return self.i <= other.i
    def __eq__(self, other):
        return self.i == other.i

assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)

Определение 2: множественное наследование

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

Термин класс mixin относится к базовым классам, которые предназначены для использования в этом шаблоне проектирования (TODO, которые используют метод, или те, которые его реализуют?)

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

Эта модель интересна тем, что можно комбинировать функции с различными вариантами выбора базовых классов:

class HasMethod1(object):
    def method(self):
        return 1

class HasMethod2(object):
    def method(self):
        return 2

class UsesMethod10(object):
    def usesMethod(self):
        return self.method() + 10

class UsesMethod20(object):
    def usesMethod(self):
        return self.method() + 20

class C1_10(HasMethod1, UsesMethod10): pass
class C1_20(HasMethod1, UsesMethod20): pass
class C2_10(HasMethod2, UsesMethod10): pass
class C2_20(HasMethod2, UsesMethod20): pass

assert C1_10().usesMethod() == 11
assert C1_20().usesMethod() == 21
assert C2_10().usesMethod() == 12
assert C2_20().usesMethod() == 22

# Nothing prevents implementing the method
# on the base class like in Definition 1:

class C3_10(UsesMethod10):
    def method(self):
        return 3

assert C3_10().usesMethod() == 13

Авторитетные появления Python

В официальной документации для collection.abc в документации явно используется термин Mixin Methods.

В нем говорится, что если класс:

  • реализует __next__
  • наследуется от одного класса Iterator

затем класс получает метод __iter__ mixin бесплатно.

Поэтому, по крайней мере, в этом пункте документации, mixin не требует множественного наследования и согласуется с определением 1.

Разумеется, документация может быть противоречивой в разные моменты, и другие важные библиотеки Python могут использовать другое определение в своей документации.

На этой странице также используется термин Set mixin, который ясно показывает, что такие классы, как Set и Iterator можно назвать классами Mixin.

На других языках

  • Ruby: Понятно, что для mixin не требуется множественное наследование, как упоминалось в основных справочниках, таких как Programming Ruby и The Ruby Language Language.

  • C++: метод, который не реализован, является чисто виртуальным методом.

    Определение 1 совпадает с определением абстрактного класса (класса, который имеет чисто виртуальный метод). Этот класс не может быть создан.

    Определение 2 возможно с виртуальным наследованием: множественное наследование от двух производных классов

Ответ 4

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

Мое понимание соглашений, которые регулируют то, что вы бы назвали миксином, таково, что миксин:

  • добавляет методы, но не переменные экземпляра (константы класса в порядке)
  • наследуется только от object (в Python)

Таким образом, он ограничивает потенциальную сложность множественного наследования и позволяет достаточно легко отслеживать поток вашей программы, ограничивая область поиска (по сравнению с полным множественным наследованием). Они похожи на модули ruby.

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

Сказав это, я видел классы с именем XYZMixin, которые имеют переменные экземпляра.

Ответ 5

Mixins - это концепция программирования, в которой класс предоставляет функциональные возможности, но не предназначен для использования для создания экземпляра. Основная цель Mixins - предоставить функциональные возможности, которые являются автономными, и было бы лучше, если бы сами микстины не имели наследования с другими миксинами, а также избегали состояния. В таких языках, как Ruby, существует некоторая поддержка прямого языка, но для Python этого нет. Тем не менее, вы могли использовать многоуровневое наследование для выполнения функций, предоставляемых в Python.

Я просмотрел это видео http://www.youtube.com/watch?v=v_uKI2NOLEM, чтобы понять основы микшинов. Для новичков очень полезно понять основы миксинов и их работу, а также проблемы, с которыми вы можете столкнуться при их реализации.

Википедия по-прежнему остается лучшей: http://en.wikipedia.org/wiki/Mixin

Ответ 6

Что отличает mixin от множественного наследования? Это просто вопрос семантики?

Миксин является ограниченной формой множественного наследования. В некоторых языках механизм добавления mixin в класс несколько отличается (в терминах синтаксиса) от наследования.

В контексте Python, в частности, mixin является родительским классом, который предоставляет функциональные возможности для подклассов, но не предназначен для создания самого себя.

Что может заставить вас сказать, "что просто множественное наследование, а не просто mixin", если класс, который может быть запутан для mixin, может быть фактически создан и использован - так что это действительно семантический и очень реальный, разница.

Пример множественного наследования

Этот пример, из документации, является OrderedCounter:

class OrderedCounter(Counter, OrderedDict):
     'Counter that remembers the order elements are first encountered'

     def __repr__(self):
         return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))

     def __reduce__(self):
         return self.__class__, (OrderedDict(self),)

Он подклассифицирует как Counter, так и OrderedDict из модуля collections.

Оба Counter и OrderedDict предназначены для создания и использования самостоятельно. Однако, подклассифицируя их оба, мы можем иметь счетчик, который упорядочен и повторно использует код в каждом объекте.

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

Пример Mixin

Микшины обычно рекламируются как способ повторного использования кода без возможных проблем связи, которые могут иметь совместное множественное наследование, например OrderedCounter. Когда вы используете mixins, вы используете функциональные возможности, которые не так тесно связаны с данными.

В отличие от вышеприведенного примера, mixin не предназначен для использования самостоятельно. Он предоставляет новые или различные функции.

Например, стандартная библиотека имеет пару mixins в библиотеке socketserver.

Можно создавать версии для вилки и потоки каждого типа сервера используя эти смешанные классы. Например, ThreadingUDPServer создается следующим образом:

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
    pass

Сначала класс mix-in, поскольку он переопределяет метод, определенный в UDPServer. Установка различных атрибутов также изменяет поведение базовый серверный механизм.

В этом случае методы mixin переопределяют методы в определении объекта UDPServer, чтобы разрешить concurrency.

Переопределенный метод выглядит как process_request, а также предоставляет другой метод process_request_thread. Здесь из исходного кода:

class ThreadingMixIn:
        """Mix-in class to handle each request in a new thread."""

        # Decides how threads will act upon termination of the
        # main process
        daemon_threads = False

        def process_request_thread(self, request, client_address):
            """Same as in BaseServer but as a thread.
            In addition, exception handling is done here.
            """
            try:
                self.finish_request(request, client_address)
            except Exception:
                self.handle_error(request, client_address)
            finally:
                self.shutdown_request(request)

        def process_request(self, request, client_address):
            """Start a new thread to process the request."""
            t = threading.Thread(target = self.process_request_thread,
                                 args = (request, client_address))
            t.daemon = self.daemon_threads
            t.start()

Проприведенный пример

Это миксин, который в основном предназначен для демонстрационных целей - большинство объектов будут выходить за рамки полезности этого представления:

class SimpleInitReprMixin(object):
    """mixin, don't instantiate - useful for classes instantiable
    by keyword arguments to their __init__ method.
    """
    __slots__ = () # allow subclasses to use __slots__ to prevent __dict__
    def __repr__(self):
        kwarg_strings = []
        d = getattr(self, '__dict__', None)
        if d is not None:
            for k, v in d.items():
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        slots = getattr(self, '__slots__', None)
        if slots is not None:
            for k in slots:
                v = getattr(self, k, None)
                kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
        return '{name}({kwargs})'.format(
          name=type(self).__name__,
          kwargs=', '.join(kwarg_strings)
          )

и использование будет:

class Foo(SimpleInitReprMixin): # add other mixins and/or extend another class here
    __slots__ = 'foo',
    def __init__(self, foo=None):
        self.foo = foo
        super(Foo, self).__init__()

И использование:

>>> f1 = Foo('bar')
>>> f2 = Foo()
>>> f1
Foo(foo='bar')
>>> f2
Foo(foo=None)

Ответ 7

Я бы посоветовал не смешивать в новый код Python, если вы можете найти какой-либо другой способ (например, композицию вместо наследования или только методы клонирования обезьяны в свои собственные классы), которая не является " гораздо больше усилий.

В классах старого стиля вы можете использовать mix-ins как способ захвата нескольких методов из другого класса. Но в мире нового стиля все, даже смешанное, наследуется от object. Это означает, что любое использование множественного наследования естественно вводит проблемы MRO.

Существуют способы сделать работу MRO с множественным наследованием в Python, в первую очередь функцией super(), но это означает, что вы должны выполнять всю свою иерархию классов с помощью функции super(), и значительно сложнее понять поток контроль.

Ответ 8

Я думаю, что здесь были хорошие объяснения, но я хотел представить еще одну перспективу.

В Scala вы можете создавать миксины, как описано здесь, но очень интересно, что микшины на самом деле "слиты" вместе, чтобы создать новый тип класса для наследования. По сути, вы не наследуете от нескольких классов /mixins, а скорее генерируете новый тип класса со всеми свойствами mixin для наследования. Это имеет смысл, так как Scala основан на JVM, где в настоящее время не поддерживается множественное наследование (как на Java 8). Этот тип типа mixin, кстати, является специальным типом, который называется Trait в Scala.

Он намекал на то, как определяется класс:   класс NewClass расширяет FirstMixin с помощью SecondMixin с ThirdMixin   ...

Я не уверен, что интерпретатор CPython делает то же самое (mixin class-composition), но я не удивлюсь. Кроме того, исходя из фона С++, я бы не назвал ABC или "интерфейс" эквивалентным mixin - это аналогичная концепция, но расходящаяся в использовании и реализации.

Ответ 9

Возможно, несколько примеров помогут.

Если вы создаете класс и хотите, чтобы он работал как словарь, вы можете определить все различные методы __ __. Но это немного боль. В качестве альтернативы вы можете просто определить несколько и наследовать (в дополнение к любому другому наследованию) от UserDict.DictMixin (перенесено в collections.DictMixin в py3k). Это приведет к автоматическому определению всего остального словаря api.

Второй пример: набор инструментов GUI wxPython позволяет создавать элементы управления списком с несколькими столбцами (например, отображение файла в проводнике Windows). По умолчанию эти списки довольно простые. Вы можете добавить дополнительные функции, такие как возможность сортировки списка по определенному столбцу, щелкнув заголовок столбца, наследуя от ListCtrl и добавляя соответствующие микшины.

Ответ 10

Это не пример Python, но в язык программирования D термин mixin используется для обозначения конструкции, используемой почти одинаково; добавив кучу вещей в класс.

В D (который, кстати, не делает MI) это делается путем вставки шаблона (думаю, что синтаксически осведомленные и безопасные макросы и вы будете близки) в область. Это позволяет использовать одну строку кода в классе, структуре, функции, модуле и т.д. Для любого количества объявлений.

Ответ 11

Может быть, пример из ruby ​​может помочь:

Вы можете включить mixin Comparable и определить одну функцию "<=>(other)", mixin предоставляет все эти функции:

<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)

Он делает это, вызывая <=>(other) и вернув правильный результат.

"instance <=> other" возвращает 0, если оба объекта равны, меньше 0, если instance больше, чем other и больше 0, если other больше.

Ответ 12

mixin дает возможность добавить функциональность в класс, т.е. вы можете взаимодействовать с методами, определенными в модуле, включая модуль внутри желаемого класса. Хотя ruby ​​не поддерживает множественное наследование, но обеспечивает mixin в качестве альтернативы для достижения этого.

вот пример, который объясняет, как достигается множественное наследование с помощью mixin.

module A    # you create a module
    def a1  # lets have a method 'a1' in it
    end
    def a2  # Another method 'a2'
    end
end

module B    # let say we have another module
    def b1  # A method 'b1'
    end
    def b2  #another method b2
    end
end

class Sample    # we create a class 'Sample'
    include A   # including module 'A' in the class 'Sample' (mixin)
    include B   # including module B as well

    def S1      #class 'Sample' contains a method 's1'
    end
end

samp = Sample.new    # creating an instance object 'samp'

# we can access methods from module A and B in our class(power of mixin)

samp.a1     # accessing method 'a1' from module A
samp.a2     # accessing method 'a2' from module A
samp.b1     # accessing method 'b1' from module B
samp.b2     # accessing method 'a2' from module B
samp.s1     # accessing method 's1' inside the class Sample

Ответ 13

Я просто использовал микс python для реализации модульного тестирования для python milters. Как правило, milter разговаривает с MTA, что затрудняет тестирование модулей. Контрольный mixin переопределяет методы, которые говорят с MTA, и создайте имитированную среду, управляемую тестовыми примерами.

Итак, вы берете немодифицированное приложение milter, например spfmilter и mixin TestBase, например:

class TestMilter(TestBase,spfmilter.spfMilter):
  def __init__(self):
    TestBase.__init__(self)
    spfmilter.config = spfmilter.Config()
    spfmilter.config.access_file = 'test/access.db'
    spfmilter.spfMilter.__init__(self)

Затем используйте TestMilter в тестовых примерах для приложения milter:

def testPass(self):
  milter = TestMilter()
  rc = milter.connect('mail.example.com',ip='192.0.2.1')
  self.assertEqual(rc,Milter.CONTINUE)
  rc = milter.feedMsg('test1',sender='[email protected]')
  self.assertEqual(rc,Milter.CONTINUE)
  milter.close()

http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup

Ответ 14

ОП упомянул, что он/она никогда не слышал о миксине в C++, возможно, это потому, что они называются CURLYURURRING Template Pattern (CRTP) в C++. Также @Ciro Santilli отметил, что mixin реализован через абстрактный базовый класс в C++. В то время как абстрактный базовый класс может использоваться для реализации mixin, это избыточное решение, поскольку функциональность виртуальной функции во время выполнения может быть достигнута с использованием шаблона во время компиляции без дополнительных затрат на поиск виртуальной таблицы во время выполнения.

Шаблон CRTP подробно описан здесь

Я преобразовал пример python в ответе @Ciro Santilli в C++, используя шаблонный класс ниже:

    #include <iostream>
    #include <assert.h>

    template <class T>
    class ComparableMixin {
    public:
        bool operator !=(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) == static_cast<T&>(other));
        }
        bool operator <(ComparableMixin &other) {
            return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
        }
        bool operator >(ComparableMixin &other) {
            return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
        }
        bool operator >=(ComparableMixin &other) {
            return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
        }
        protected:
            ComparableMixin() {}
    };

    class Integer: public ComparableMixin<Integer> {
    public:
     Integer(int i) {
         this->i = i;
     }
     int i;
     bool operator <=(Integer &other) {
         return (this->i <= other.i);
     }
     bool operator ==(Integer &other) {
         return (this->i == other.i);
     }
    };

int main() {

    Integer i(0) ;
    Integer j(1) ;
    //ComparableMixin<Integer> c; // this will cause compilation error because constructor is protected.
    assert (i < j );
    assert (i != j);
    assert (j >  i);
    assert (j >= i);

    return 0;
}

РЕДАКТИРОВАТЬ: Добавлен защищенный конструктор в ComparableMixin, так что он может быть только унаследован и не создан. Обновлен пример, чтобы показать, как защищенный конструктор будет вызывать ошибку компиляции при создании объекта ComparableMixin.

Ответ 15

Я прочитал, что у вас есть С# background. Поэтому хорошей отправной точкой может быть реализация mixin для .NET.

Возможно, вы захотите проверить проект codeplex на http://remix.codeplex.com/

Посмотрите на ссылку lang.net Symposium, чтобы получить обзор. На странице Codeplex еще есть что посмотреть.

С уважением Стефан

Ответ 16

Re @ Ответ Сиро Сантилли: на самом деле можно использовать второе определение mixins в С++ с помощью интерфейсов

#include <iostream>

struct Interface {
    virtual int method() const = 0;
};

class HasMethod1 : public virtual Interface {
    int method() const {return 1;}
};

class HasMethod2 : public virtual Interface {
    int method() const {return 2;}
};

class UsesMethod10 : public virtual Interface {
public:
    int usesMethod() const {return 10+method();}
};

class UsesMethod20 : public virtual Interface {
public:
    int usesMethod() const {return 20+method();}
};

template <typename T1, typename T2>
struct Combination : public T1, public T2 {
};

int main() {
    std::cout << Combination<HasMethod1, UsesMethod10>().usesMethod() << std::endl;
    std::cout << Combination<HasMethod2, UsesMethod10>().usesMethod() << std::endl;
    std::cout << Combination<HasMethod1, UsesMethod20>().usesMethod() << std::endl;
    std::cout << Combination<HasMethod2, UsesMethod20>().usesMethod() << std::endl;

    return 0;
}

Возможно, было бы лучше использовать форму CRTP, чтобы сделать это, но я не собираюсь идти за борт здесь.

Ответ 17

Во-первых, вы должны заметить, что миксины существуют только в языках множественного наследования. Вы не можете сделать миксин в Java или С#.

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

По сути, миксин - это автономный базовый тип, который обеспечивает ограниченную функциональность и полиморфный резонанс для дочернего класса. Если вы думаете о С#, подумайте об интерфейсе, который вам не нужно реализовывать, потому что он уже реализован; вы просто наследуете его и извлекаете выгоду из его функциональности.

Миксины обычно узкие по объему и не предназначены для расширения.