В объектно-ориентированных языках программирования , A Mixin (или примесь ) [1] [2] [3] [4] представляет собой класс , который содержит методы для использования других классов без того , чтобы быть родительским класс этих других классов. Как эти другие классы получают доступ к методам миксина, зависит от языка. Миксины иногда описываются как «включенные», а не «унаследованные».
Миксины поощряют повторное использование кода и могут использоваться, чтобы избежать неоднозначности наследования, которую может вызвать множественное наследование [5] (« проблема ромба »), или для решения проблемы отсутствия поддержки множественного наследования в языке. Миксин также можно рассматривать как интерфейс с реализованными методами . Этот шаблон является примером реализации принципа инверсии зависимостей .
История
Впервые миксины появились в объектно-ориентированной системе Flavors от Symbolics (разработанной Говардом Кэнноном), которая представляла собой подход к объектной ориентации, используемый в Lisp Machine Lisp . Название было вдохновлено кафе-мороженым Стива в Сомервилле, штат Массачусетс: [1] Владелец магазина мороженого предложил базовый вкус мороженого (ваниль, шоколад и т. Д.) И смешал с комбинацией дополнительных продуктов (орехи, файлы cookie, фадж и т. д.) и назвал этот элемент « примесью », что в то время было его собственным товарным знаком. [2]
Определение
Миксины - это языковая концепция, которая позволяет программисту внедрять некоторый код в класс . Программирование миксинов - это стиль разработки программного обеспечения , при котором функциональные единицы создаются в классе, а затем смешиваются с другими классами. [6]
Класс миксина действует как родительский класс, содержащий желаемую функциональность. Затем подкласс может наследовать или просто повторно использовать эту функциональность, но не как средство специализации. Обычно миксин экспортирует желаемую функциональность в дочерний класс , не создавая жесткой, единственной связи "есть". В этом заключается важное различие между концепциями миксинов и наследования в том, что дочерний класс по-прежнему может наследовать все функции родительского класса, но семантика о том, что дочерний элемент «является разновидностью» родителя, не обязательно должна применяться.
Преимущества
- Он обеспечивает механизм множественного наследования , позволяя одному классу использовать общие функции нескольких классов, но без сложной семантики множественного наследования. [7]
- Возможность повторного использования кода : миксины полезны, когда программист хочет разделить функциональность между разными классами. Вместо того, чтобы повторять один и тот же код снова и снова, общие функции можно просто сгруппировать в миксин, а затем включить в каждый класс, который этого требует. [8]
- Миксины позволяют наследовать и использовать только желаемые функции родительского класса, а не обязательно все функции родительского класса. [9]
Реализации
В Simula классы определены в блоке, в котором атрибуты, методы и инициализация классов определены вместе; таким образом, все методы, которые могут быть вызваны в классе, определены вместе, и определение класса завершено.
В Flavors миксин - это класс, от которого другой класс может наследовать определения и методы слотов. У миксина обычно нет прямых экземпляров. Поскольку Flavor может наследовать более чем от одного другого Flavor, он может наследовать от одного или нескольких миксинов. Обратите внимание, что в исходных версиях Flavors не использовались общие функции.
В New Flavors (преемнике Flavors) и CLOS методы организованы в « общие функции ». Эти универсальные функции - это функции, которые определяются в нескольких случаях (методах) с помощью диспетчеризации классов и комбинаций методов.
CLOS и Flavors позволяют методам миксина добавлять поведение к существующим методам: :before
а также :after
демонам, громадинам и оболочкам во Flavors. В CLOS добавлены :around
методы и возможность вызова теневых методов через CALL-NEXT-METHOD
. Так, например, миксин-блокировка-поток может добавить блокировку для существующих методов класса потока. В Flavors можно написать обертку или громадину, а в CLOS использовать :around
метод. И CLOS, и Flavors допускают повторное использование вычислений с помощью комбинаций методов. :before
, :after
и :around
методы являются особенностью стандартной комбинации методов. Предусмотрены другие комбинации методов.
Примером является +
комбинация методов, где результирующие значения каждого из применимых методов универсальной функции арифметически складываются для вычисления возвращаемого значения. Это используется, например, с примесью границы для графических объектов. Графический объект может иметь универсальную функцию ширины. Примесь границы добавит границу вокруг объекта и имеет метод, вычисляющий его ширину. Новый класс bordered-button
(который одновременно является графическим объектом и использует border
миксин) будет вычислять его ширину, вызывая все применимые методы ширины - через +
комбинацию методов. Все возвращаемые значения добавляются и создают общую ширину объекта.
В статье OOPSLA 90 [10] Гилад Браха и Уильям Кук заново интерпретируют различные механизмы наследования, обнаруженные в Smalltalk, Beta и CLOS, как особые формы наследования миксинов.
Языки программирования, использующие миксины
Помимо Flavors и CLOS (часть Common Lisp ), некоторые языки, которые используют миксины:
- Ада (путем расширения существующей записи с тегами произвольными операциями в универсальном)
- Кобра
- ColdFusion (на основе классов с использованием включает и на основе объектов путем назначения методов от одного объекта другому во время выполнения)
- Curl (с Curl RTE)
- D (называемый «шаблонными миксинами» ; D также включает оператор «миксин», который компилирует строки как код.)
- Дротик
- Фактор [11]
- Groovy
- Делегирование JavaScript - функции как роли (черты и миксы)
- Котлин
- Меньше
- OCaml
- Perl (через роли в расширении Moose объектной системы Perl 5)
- PHP «ы„ черта “
- Мэджик
- MATLAB [12]
- Python
- Ракетка ( документация миксинов )
- Раку
- Рубин
- Скала [13]
- XOTcl / TclOO (объектные системы, встроенные в Tcl ) [14]
- Sass (язык таблиц стилей)
- Болтовня
- Вала
- Быстрый
- SystemVerilog
- TypeScript ( документация миксинов )
Некоторые языки не поддерживают миксины на уровне языка, но могут легко имитировать их, копируя методы из одного объекта в другой во время выполнения, тем самым «заимствуя» методы миксина. Это также возможно со статически типизированными языками, но для этого требуется создание нового объекта с расширенным набором методов.
Другие языки, не поддерживающие миксины, могут поддерживать их в обходной форме через другие языковые конструкции. C # и Visual Basic .NET поддерживают добавление методов расширения в интерфейсы, что означает, что любой класс, реализующий интерфейс с определенными методами расширения, будет иметь методы расширения, доступные как псевдо-члены.
Примеры
В Common Lisp
Common Lisp предоставляет миксины в CLOS (Common Lisp Object System), аналогичные Flavors.
object-width
- это универсальная функция с одним аргументом, использующая +
комбинацию методов. Эта комбинация определяет, что все применимые методы для универсальной функции будут вызваны, а результаты будут добавлены.
( defgeneric object-width ( объект ) ( : комбинация методов + ))
button
- это класс с одним слотом для текста кнопки.
( кнопка defclass () (( текст : initform "щелкните меня" )))
Существует метод для объектов класса button, который вычисляет ширину на основе длины текста кнопки. +
квалификатор метода для одноименной комбинации методов.
( defmethod object-width + (( кнопка объекта )) ( * 10 ( длина ( текст объекта со значением слота ))))
border-mixin
Класс. Именование - это просто соглашение. Нет ни суперклассов, ни слотов.
( defclass- граница-миксин () ())
Есть метод вычисления ширины границы. Здесь их всего 4.
( defmethod object-width + (( объект- граница-миксин )) 4 )
bordered-button
- это класс, унаследованный от обоих border-mixin
и button
.
( DEFCLASS граничила кнопки ( границы Mixin кнопка ) ())
Теперь мы можем вычислить ширину кнопки. Вызов object-width
вычисляет 80. Результат является результатом единственного применимого метода: метода object-width
для класса button
.
? ( ширина объекта ( кнопка создания экземпляра )) 80
Мы также можем вычислить ширину a bordered-button
. Вызов object-width
вычисляет 84. Результатом является сумма результатов двух применимых методов: метода object-width
для класса button
и метода object-width
для класса border-mixin
.
? ( ширина объекта ( кнопка make-instance 'с рамкой )) 84
В Python
В Python , то SocketServer
модуль [15] имеет как UDPServer
класс и TCPServer
класс. Они действуют как серверы для серверов сокетов UDP и TCP соответственно. Кроме того, есть два класса миксинов: ForkingMixIn
и ThreadingMixIn
. Обычно все новые соединения обрабатываются в рамках одного процесса. Расширяя TCPServer
их ThreadingMixIn
следующим образом:
класс ThreadingTCPServer ( ThreadingMixIn , TCPServer ): пройти
ThreadingMixIn
класс расширяет функциональные возможности сервера TCP таким образом, что каждое новое соединение создает новую нить . Используя тот же метод, ThreadingUDPServer
можно создать объект без дублирования кода в ThreadingMixIn
. В качестве альтернативы, использование ForkingMixIn
вызовет разветвление процесса для каждого нового соединения. Ясно, что возможность создания нового потока или разветвления процесса не очень полезна как отдельный класс.
В этом примере использования миксины обеспечивают альтернативную базовую функциональность, не влияя на функциональность в качестве сервера сокетов.
В Ruby
Большая часть мира Ruby основана на миксинах через Modules
. Концепция миксинов реализована в Ruby с помощью ключевого слова, include
которому мы передаем имя модуля в качестве параметра .
Пример:
Класс Student включают Comparable # Класс Student наследует Comparable модуль с помощью «включать» ключевое слово attr_accessor : имя , : оценка def initialize ( имя , оценка ) @name = имя @score = оценка конец # Включение модуля Comparable требует, чтобы реализующий класс определил оператор сравнения <=> # Вот оператор сравнения. Мы сравниваем 2 экземпляра студентов на основе их оценок. def <=> ( другое ) @score <=> другое . конец счета # Хороший момент - я получаю бесплатный доступ к <, <=,>,> = и другим методам Comparable Interface. конецs1 = Студент . new ( "Питер" , 100 ) s2 = Студент . новый ( "Джейсон" , 90 )s1 > s2 # true s1 <= s2 # false
В JavaScript
Объектно-Буквальное и extend
подход
Технически возможно добавить поведение к объекту, привязав функции к ключам в объекте. Однако это отсутствие разделения между состоянием и поведением имеет недостатки:
- Он смешивает свойства области модели со свойствами области реализации.
- Нет разделения общего поведения. Метаобъекты решают эту проблему, отделяя специфичные для предметной области свойства объектов от специфических свойств их поведения. [16]
Функция расширения используется для смешивания поведения в: [17]
'использовать строго' ;const Halfling = функция ( fName , lName ) { this . firstName = fName ; это . lastName = lName ; };const mixin = { fullName () { верните это . firstName + '' + this . lastName ; }, переименовать ( первый , последний ) { this . firstName = первое ; это . lastName = last ; вернуть это ; } };// Функция расширения const extend = ( obj , mixin ) => { Object . ключи ( миксин ). forEach ( ключ => объект [ ключ ] = миксин [ ключ ]); return obj ; };const sam = новый халфлинг ( 'Сэм' , 'Лаври' ); const frodo = новый халфлинг ( 'Фрида' , 'Баггс' );// Mixin другие методы расширения ( Halfling . Прототип , подмешать );консоль . журнал ( sam . fullName ()); // Сэм Лаури console . журнал ( frodo . fullName ()); // Фрида БэггсСэм . переименовать ( «Samwise» , «Gamgee» ); Фродо . переименовать ( «Фродо» , «Бэггинс» );консоль . журнал ( sam . fullName ()); // Samwise Gamgee console . журнал ( frodo . fullName ()); // Фродо Бэггинс
Смешивание с использованием Object.assign ()
'использовать строго' ;// Создание объекта const obj1 = { имя : 'Марк Аврелий' , город : 'Рим' , дата рождения : '121-04-26' };// Mixin 1 const mix1 = { toString () { return ` $ { this . name } родился в $ { this . city } в $ { this . born } ` ; }, age () { const год = новая дата (). getFullYear (); Const родился = новая Дата ( это . родилось ). getFullYear (); вернуться год - родился ; } }; // Mixin 2 const mix2 = { toString () { return ` $ { this . name } - $ { this . city } - $ { this . born } ` ; } };// Добавление методов из миксинов к объекту с помощью Object.assign () Object . назначить ( obj1 , mix1 , mix2 );консоль . журнал ( obj1 . toString ()); // Марк Аврелий - Рим - 121-04-26 консоль . войти ( `Его возраст составляет $ { obj1 . возраст () } от today` ); // На сегодняшний день ему 1897 год.
Подход Flight-Mixin, основанный на чистых функциях и делегировании
Несмотря на то, что первый описанный подход в основном широко распространен, следующий ближе к тому, что в основе своей предлагает ядро языка JavaScript - делегирование .
Два шаблона, основанные на функциональных объектах, уже справляются со своей задачей без необходимости сторонней реализации extend
.
'использовать строго' ;// Реализация const EnumerableFirstLast = ( function () { // шаблон модуля на основе функции. Const first = function () { return this [ 0 ]; }, last = function () { return this [ this . Length - 1 ]; } ; return function () { // основанная на функциях механика Flight-Mixin ... this . first = first ; // ... ссылка на ... this . last = last ; // ... общий код. }; } ());// Приложение - явное делегирование: // применение перечислимого поведения [first] и [last] к [прототипу] [Array]. EnumerableFirstLast . вызов ( массив . прототип );// Теперь вы можете: const a = [ 1 , 2 , 3 ]; а . первый (); // 1 а . последний (); // 3
На других языках
В языке веб-контента Curl используется множественное наследование, поскольку классы без экземпляров могут реализовывать методы. Общие миксины включают в себя все скины, ControlUI
наследуемые от SkinnableControlUI
объектов делегатов пользовательского интерфейса, которые требуют раскрывающихся меню, унаследованных от StandardBaseDropdownUI и таких явно названных классов миксинов, как FontGraphicMixin
, FontVisualMixin
и NumericAxisMixin-of
class. В версии 7.0 добавлен доступ к библиотеке, так что миксины не обязательно должны находиться в одном пакете или быть общедоступными абстракциями. Конструкторы Curl - это фабрики, которые упрощают использование множественного наследования без явного объявления интерфейсов или миксинов. [ необходима цитата ]
Интерфейсы и особенности
В Java 8 представлена новая функция в виде методов по умолчанию для интерфейсов. [18] В основном это позволяет определять метод в интерфейсе с приложением в сценарии, когда новый метод должен быть добавлен к интерфейсу после завершения настройки программирования класса интерфейса. Добавление новой функции к интерфейсу означает реализацию метода в каждом классе, использующем интерфейс. В этом случае помогают методы по умолчанию, когда они могут быть введены в интерфейс в любое время и имеют реализованную структуру, которая затем используется соответствующими классами. Следовательно, методы по умолчанию добавляют возможность применения концепции в виде миксинов.
Интерфейсы в сочетании с аспектно-ориентированным программированием также могут создавать полноценные миксины на языках, поддерживающих такие функции, таких как C # или Java. Кроме того, за счет использования шаблона интерфейса маркера , универсального программирования и методов расширения C # 3.0 имеет возможность имитировать миксины. В C # 3.0 появились методы расширения, которые можно применять не только к классам, но и к интерфейсам. Методы расширения предоставляют дополнительную функциональность для существующего класса без изменения класса. Затем становится возможным создать статический вспомогательный класс для конкретной функциональности, определяющей методы расширения. Поскольку классы реализуют интерфейс (даже если фактический интерфейс не содержит каких-либо методов или свойств для реализации), он также подберет все методы расширения. [3] [4] [19] В C # 8.0 добавлена функция методов интерфейса по умолчанию. [20]
ECMAScript (в большинстве случаев реализованный как JavaScript) не требует имитации композиции объекта путем пошагового копирования полей из одного объекта в другой. Он изначально [21] поддерживает композицию объектов на основе Trait и mixin [22] [23] через функциональные объекты, которые реализуют дополнительное поведение, а затем делегируются через call
или apply
объектам, которые нуждаются в такой новой функциональности.
В Scala
Scala имеет богатую систему типов, и трейты являются ее частью, которая помогает реализовать поведение миксинов. Как следует из их названия, Traits обычно используются для представления отдельной функции или аспекта, который обычно ортогонален ответственности конкретного типа или, по крайней мере, определенного экземпляра. [24] Например, способность петь моделируется как такая ортогональная характеристика: ее можно применить к птицам, людям и т. Д.
trait Singer { def sing { println ( "пение…" ) } // другие методы }класс Bird расширяет Singer
Здесь Bird смешал все методы признака в своем собственном определении, как если бы класс Bird определил метод sing () сам по себе.
Как extends
также используется для наследования от суперкласса, в случае признака extends
используется, если суперкласс не наследуется, и только для примеси в первом признаке. Все следующие черты смешаны в использовании ключевого слова with
.
class Person класс Actor расширяет Person с помощью Singer класс Actor расширяет Singer с помощью Performer
Scala позволяет смешивать трейт (создавать анонимный тип ) при создании нового экземпляра класса. В случае экземпляра класса Person не все экземпляры могут петь. Эта функция пригодится тогда:
class Person { def tell { println ( "Human" ) } // дополнительные методы }val singingPerson = новый человек с певцом singingPerson . петь
В Swift
Mixin может быть реализован в Swift с помощью языковой функции, называемой реализацией по умолчанию в расширении протокола.
protocol ErrorDisplayable { ошибка func ( сообщение : строка )}extension ErrorDisplayable { func error ( message : String ) { // Делаем то, что нужно, чтобы показать ошибку // ... печать ( сообщение ) }}struct NetworkManager : ErrorDisplayable { func onError () { ошибка ( «Пожалуйста, проверьте подключение к Интернету.» ) }}
Смотрите также
- Абстрактный тип
- Шаблон декоратора
- Дизайн на основе политик
- Признак , похожая структура, не требующая линейной композиции
Рекомендации
- ^ a b Использование миксов с Python
- ^ a b Mix-Ins (Мороженое Стива, Бостон, 1975). Архивировано 26 октября 2007 г. в Wayback Machine.
- ^ a b Реализация смешивания с методами расширения C #
- ^ a b Я знаю ответ (его 42): Mix-ins и C #
- ^ Бойленд, Джон; Джузеппе Кастанья (26 июня 1996 г.). «Типобезопасная компиляция ковариантной специализации: практический пример» . В Пьера Коэнта (ред.). ECOOP '96, Объектно-ориентированное программирование: 10-я Европейская конференция . Springer. С. 16–17. ISBN 9783540614395. Проверено 17 января 2014 года .
- ^ http://c2.com/cgi/wiki?MixIn
- ^ http://culttt.com/2015/07/08/working-with-mixins-in-ruby/
- ^ http://naildrivin5.com/blog/2012/12/19/re-use-in-oo-inheritance.html
- ^ «Архивная копия» . Архивировано из оригинала на 2015-09-25 . Проверено 16 сентября 2015 .CS1 maint: заархивированная копия как заголовок ( ссылка )
- ^ OOPSLA '90, Наследование на основе Mixin (pdf)
- ^ слава (25.01.2010). «Фактор / Особенности / Язык» . concatenative.org . Проверено 15 мая 2012 .
Основные языковые особенности Factor:… объектная система с наследованием, универсальными функциями, отправкой предикатов и миксинами.
Внешняя ссылка в|publisher=
( помощь ) - ^ https://in.mathworks.com/help/matlab/mixin-classes.html
- ^ «Состав класса Mixin» . Федеральная политехническая школа Лозанны . Дата обращения 16 мая 2014 .
- ^ Классы миксинов в XOTcl
- ^ Исходный код SocketServer в CPython 3.5
- ^ http://raganwald.com/2014/04/10/mixins-forwarding-delegation.html
- ^ «Архивная копия» . Архивировано из оригинала на 2015-09-21 . Проверено 16 сентября 2015 .CS1 maint: заархивированная копия как заголовок ( ссылка )
- ^ https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
- ^ Миксины, дженерики и методы расширения в C #
- ^ Смешайте функциональность при создании классов с использованием интерфейсов с методами интерфейса по умолчанию
- ^ Многочисленные возможности JavaScript для обобщения подходов к ролевому программированию, таких как Traits и Mixins , 11 апреля 2014 г.
- ^ Ангус Кролл, Свежий взгляд на миксины JavaScript , опубликовано 31 мая 2011 г.
- ^ Шаблоны повторного использования кода JavaScript , 19 апреля 2013 г.
- ^ https://gleichmann.wordpress.com/2009/07/19/scala-in-practice-traits-as-mixins-motivation
Внешние ссылки
- MixIn в Портлендском репозитории паттернов
- Миксины в ActionScript
- Система Common Lisp Object: Обзор по Ричарду П. Габриэлю и Линда DeMichiel обеспечивает хорошее введение в мотивацию для определения классов с помощью общих функций.