stringtranslate.com

Миксин

В объектно-ориентированных языках программирования миксин (или mix -in ) [1] [2] [3] [4] — это класс , содержащий методы для использования другими классами, не будучи родительским классом этих других классов. То, как эти другие классы получают доступ к методам миксина, зависит от языка. Миксины иногда описываются как «включенные», а не «унаследованные».

Миксины поощряют повторное использование кода и могут использоваться для избежания неоднозначности наследования, которую может вызвать множественное наследование [5]проблема ромба »), или для обхода отсутствия поддержки множественного наследования в языке. Миксин также можно рассматривать как интерфейс с реализованными методами . Этот шаблон является примером реализации принципа инверсии зависимостей .

История

Миксины впервые появились в объектно-ориентированной системе Flavors компании Symbolics (разработанной Говардом Кэнноном), которая представляла собой подход к объектной ориентации, используемый в Lisp Machine Lisp . Название было навеяно кафе-мороженым Steve's Ice Cream Parlor в Сомервилле, штат Массачусетс: [1] Владелец магазина мороженого предлагал базовый вкус мороженого (ваниль, шоколад и т. д.) и смешивал его с комбинацией дополнительных ингредиентов (орехи, печенье, помадка и т. д.) и называл этот ингредиент « микс-ином », что в то время было его собственным зарегистрированным термином. [2]

Определение

Миксины — это языковая концепция, которая позволяет программисту вводить некоторый код в класс . Миксиновое программирование — это стиль разработки программного обеспечения , в котором единицы функциональности создаются в классе, а затем смешиваются с другими классами. [6]

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

Преимущества

  1. Он обеспечивает механизм множественного наследования , позволяя одному классу использовать общую функциональность из нескольких классов, но без сложной семантики множественного наследования. [7]
  2. Повторное использование кода : миксины полезны, когда программист хочет разделить функциональность между различными классами. Вместо того, чтобы повторять один и тот же код снова и снова, общую функциональность можно просто сгруппировать в миксин, а затем включить в каждый класс, которому она требуется. [8]
  3. Миксины позволяют наследование и использование только желаемых функций родительского класса, а не обязательно всех функций родительского класса. [9]

Реализации

В Simula классы определяются в блоке, в котором атрибуты, методы и инициализация класса определяются вместе; таким образом, все методы, которые могут быть вызваны для класса, определяются вместе, и определение класса является полным.

В Flavors миксин — это класс, из которого другой класс может наследовать определения слотов и методы. Миксин обычно не имеет прямых экземпляров. Поскольку Flavor может наследовать от более чем одного другого Flavor, он может наследовать от одного или нескольких миксинов. Обратите внимание, что оригинальные Flavors не использовали универсальные функции.

В New Flavors (преемнике Flavors) и CLOS методы организованы в « универсальные функции ». Эти универсальные функции — это функции, которые определены в нескольких случаях (методах) с помощью диспетчеризации классов и комбинаций методов.

CLOS и Flavors позволяют методам mixin добавлять поведение к существующим методам: :beforeи :afterдемонам, вопперам и оберткам в Flavors. CLOS добавил :aroundметоды и возможность вызывать затененные методы через CALL-NEXT-METHOD. Так, например, stream-lock-mixin может добавлять блокировку вокруг существующих методов потокового класса. В Flavors можно было бы написать обертку или воппер, а в CLOS можно было бы использовать метод :around. И CLOS, и Flavors допускают вычисляемое повторное использование через комбинации методов. :before, :afterа :aroundметоды являются функцией стандартной комбинации методов. Предоставляются и другие комбинации методов.

Примером является +комбинация методов, где результирующие значения каждого из применимых методов универсальной функции арифметически складываются для вычисления возвращаемого значения. Это используется, например, с border-mixin для графических объектов. Графический объект может иметь универсальную функцию ширины. border-mixin добавит границу вокруг объекта и имеет метод, вычисляющий его ширину. Новый класс bordered-button(который является одновременно графическим объектом и использует bordermixin) вычислит его ширину, вызывая все применимые методы ширины — через +комбинацию методов. Все возвращаемые значения складываются и создают объединенную ширину объекта.

В статье OOPSLA 90 [10] Гилад Браха и Уильям Кук переосмысливают различные механизмы наследования, обнаруженные в Smalltalk, Beta и CLOS, как особые формы наследования миксинов.

Языки программирования, использующие миксины

Помимо Flavors и CLOS (часть Common Lisp ), вот некоторые языки, которые используют миксины:

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

Другие языки, не поддерживающие миксины, могут поддерживать их обходным путем через другие языковые конструкции. Например, Visual Basic .NET и C# поддерживают добавление методов расширения в интерфейсы, что означает, что любой класс, реализующий интерфейс с определенными методами расширения, будет иметь методы расширения, доступные как псевдочлены.

Примеры

В Common Lisp

Common Lisp предоставляет миксины в CLOS (Common Lisp Object System), аналогичные Flavors.

object-width— это универсальная функция с одним аргументом, которая использует +комбинацию методов. Эта комбинация определяет, что будут вызваны все применимые методы для универсальной функции, а результаты будут добавлены.

( defgeneric object-width ( object ) ( :method-combination + ))    

buttonэто класс с одним слотом для текста кнопки.

( defclass button () (( text :initform "нажми меня" )))     

Для объектов класса button существует метод, который вычисляет ширину на основе длины текста кнопки. +— это квалификатор метода для комбинации методов с тем же именем.

( defmethod object-width + (( object button )) ( * 10 ( length ( slot-value object 'text ))))          

Класс border-mixin. Наименование — это просто соглашение. Нет суперклассов и слотов.

( defclass border-mixin () ())   

Есть метод вычисления ширины границы. Здесь она равна всего 4.

( defmethod object-width + (( object border-mixin )) 4 )     

bordered-button— это класс, наследующий как от , так border-mixinи от button.

( defclass bordered-button ( border-mixin button ) ())    

Теперь мы можем вычислить ширину кнопки. Вызов object-widthвычисляет 80. Результат — это результат единственного применимого метода: метода object-widthдля класса button.

? ( ​​ширина-объекта ( кнопка создания-экземпляра )) 80   

Мы также можем вычислить ширину a bordered-button. Вызов object-widthcomputes 84. Результат представляет собой сумму результатов двух применимых методов: метода object-widthдля класса buttonи метода object-widthдля класса border-mixin.

? ( ​​ширина-объекта ( сделать-экземпляр ' кнопка-окантовка )) 84   

На языке питона

В Python пример концепции mixin можно найти в SocketServerмодуле [17] , который имеет как UDPServerкласс, так и TCPServerкласс. Они действуют как серверы для серверов сокетов UDP и TCP соответственно. Кроме того, есть два mixin-класса: ForkingMixInи ThreadingMixIn. Обычно все новые соединения обрабатываются в рамках одного процесса. При расширении TCPServerс помощью ThreadingMixInследующим образом:

класс  ThreadingTCPServer ( ThreadingMixIn ,  TCPServer ):  проход

класс ThreadingMixInдобавляет функциональность к TCP-серверу, так что каждое новое соединение создает новый поток . Используя тот же метод, ThreadingUDPServerможно создать без необходимости дублировать код в ThreadingMixIn. В качестве альтернативы использование ForkingMixInприведет к разветвлению процесса для каждого нового соединения. Очевидно, что функциональность создания нового потока или разветвления процесса не очень полезна в качестве отдельного класса.

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

В рубине

Большая часть мира Ruby основана на миксинах через Modules. Концепция миксинов реализована в Ruby ключевым словом include, которому мы передаем имя модуля в качестве параметра .

Пример:

class Student include Comparable # Класс Student наследует модуль Comparable с помощью ключевого слова 'include' attr_accessor :name , :score        def initialize ( имя , счет ) @имя = имя @счет = счет конец          # Включение модуля Comparable требует, чтобы реализующий класс определил оператор сравнения <=> # Вот оператор сравнения. Мы сравниваем 2 экземпляра студентов на основе их оценок.  def <=> ( другое ) @score <=> другое . оценка конец      # А вот и хорошая часть - я получаю доступ к <, <=, >,>= и другим методам Comparable Interface бесплатно. конецs1 = Студент . новый ( "Питер" , 100 ) s2 = Студент . новый ( "Джейсон" , 90 )      s1 > s2 #истина s1 <= s2 #ложь      

В JavaScript

Объект -буквальный и extendподход

Технически возможно добавить поведение к объекту, привязав функции к ключам в объекте. Однако это отсутствие разделения между состоянием и поведением имеет недостатки:

  1. Он смешивает свойства области модели со свойствами области реализации.
  2. Никакого разделения общего поведения. Метаобъекты решают эту проблему, отделяя доменно-специфические свойства объектов от их поведенческих специфических свойств. [18]

Функция расширения используется для смешивания поведения в: [19]

«использовать строго» ;const Halfling = function ( fName , lName ) { this.firstName = fName ; this.lastName = lName ; } ;            const mixin = { fullName ( ) { return this.firstName + ' ' + this.lastName ; } , rename ( first , last ) { this.firstName = first ; this.lastName = last ; return this ; } } ;                        // Функция расширения const extend = ( obj , mixin ) => { Object . keys ( mixin ). forEach ( key => obj [ key ] = mixin [ key ]); return obj ; };             const sam = new Halfling ( 'Сэм' , 'Лоури' ); const frodo = new Halfling ( 'Фрида' , 'Бэггс' );          // Примешиваем другие методы extend ( Halfling . prototype , mixin ); console.log ( sam.fullName ( )); // Сэм Лоури console.log ( frodo.fullName ( ) ) ; // Фрида Бэггс  sam.rename ( 'Сэмвайс' , ' Гэмджи ' ) ; frodo.rename ( 'Фродо' , 'Бэггинс' ) ;  console.log ( sam.fullName ( ) ); // Сэм Гэмджи console.log ( frodo.fullName () ) ; // Фродо Бэггинс  

Миксин с использованием Object.assign()

«использовать строго» ;// Создание объекта const obj1 = { name : 'Марк Аврелий' , city : 'Рим' , born : '121-04-26' };         // Миксин 1 const mix1 = { toString ( ) { return ` $ { this.name } родился в ${ this.city } в ${ this.born } ` ; }, age ( ) { const year = new Date (). getFullYear ( ) ; const born = new Date ( this.born ) .getFullYear ( ) ; return year - born ; } } ; // Миксин 2 const mix2 = { toString ( ) { return ` $ { this.name } - $ { this.city } - $ { this.born } ` ; } } ;                                 // Добавляем методы из миксинов к объекту с помощью Object.assign( ) Object.assign ( obj1 , mix1 , mix2 ) ;  console.log ( obj1.toString ( ) ); // Марк Аврелий - Рим - 121-04-26 console.log ( `Его возраст $ { obj1.age () } на сегодняшний день` ) ; // Его возраст 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 ; // ... общий код. }; }());                                       // Применение - явное делегирование: // применение [первого] ​​и [последнего] перечислимого поведения к [прототипу] [Array]. EnumerableFirstLast . call ( Array . prototype );// Теперь вы можете сделать: const a = [ 1 , 2 , 3 ]; a . first (); // 1 a . last (); // 3       

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

В языке веб-контента Curl используется множественное наследование, поскольку классы без экземпляров могут реализовывать методы. Обычные миксины включают все скины ControlUI, наследуемые от SkinnableControlUI, объекты делегатов пользовательского интерфейса, которым требуются выпадающие меню, наследуемые от StandardBaseDropdownUI, и такие явно именованные классы миксинов, как FontGraphicMixin, FontVisualMixinи NumericAxisMixin-ofclass. В версии 7.0 добавлен доступ к библиотеке, так что миксины не должны находиться в одном пакете или быть общедоступными абстрактными. Конструкторы Curl — это фабрики, которые облегчают использование множественного наследования без явного объявления интерфейсов или миксинов. [ необходима цитата ]

Интерфейсы и характеристики

Java 8 представляет новую функцию в виде методов по умолчанию для интерфейсов. [20] По сути, это позволяет определить метод в интерфейсе с применением в сценарии, когда новый метод должен быть добавлен к интерфейсу после завершения настройки программирования класса интерфейса. Добавить новую функцию к интерфейсу означает реализовать метод в каждом классе, который использует интерфейс. Методы по умолчанию помогают в этом случае, поскольку они могут быть введены в интерфейс в любое время и имеют реализованную структуру, которая затем используется связанными классами. Следовательно, методы по умолчанию добавляют возможность применять концепцию миксина в Java.

Интерфейсы в сочетании с аспектно-ориентированным программированием также могут создавать полноценные миксины в языках, которые поддерживают такие возможности, таких как C# или Java. Кроме того, благодаря использованию шаблона интерфейса маркера , обобщенного программирования и методов расширения, C# 3.0 имеет возможность имитировать миксины. С Dart 2.7 и C# 3.0 появились методы расширения, которые можно применять не только к классам, но и к интерфейсам. Методы расширения предоставляют дополнительную функциональность существующему классу без изменения класса. Затем становится возможным создать статический вспомогательный класс для определенной функциональности, который определяет методы расширения. Поскольку классы реализуют интерфейс (даже если фактический интерфейс не содержит никаких методов или свойств для реализации), он также подхватит все методы расширения. [3] [4] [21] C# 8.0 добавляет функцию методов интерфейса по умолчанию. [22] [23]

ECMAScript (в большинстве случаев реализованный как JavaScript) не нуждается в имитации композиции объектов путем пошагового копирования полей из одного объекта в другой. Он изначально [24] поддерживает композицию объектов на основе Trait и mixin [25] [26] через функциональные объекты, которые реализуют дополнительное поведение, а затем делегируются через callили applyобъектам, которым нужна такая новая функциональность.

В Скале

Scala имеет богатую систему типов, и черты являются ее частью, которая помогает реализовать поведение миксина. Как видно из их названия, черты обычно используются для представления отдельной функции или аспекта, который обычно ортогонален ответственности конкретного типа или, по крайней мере, определенного экземпляра. [27] Например, способность петь моделируется как такая ортогональная функция: ее можно применять к птицам, людям и т. д.

черта Певец { def sing { println ( " пение … " ) } //еще методы }       класс Птица расширяет Певицу   

Здесь Bird смешал все методы признака в своем собственном определении, как если бы класс Bird определил метод sing() самостоятельно.

As extendsтакже используется для наследования от суперкласса, в случае, если черта extendsиспользуется, если суперкласс не унаследован, и только для примеси в первой черте. Все последующие черты смешиваются с использованием ключевого слова with.

класс Person класс Actor расширяет Person с Singer класс Actor расширяет Singer с Performer           

Scala позволяет смешивать черты (создавать анонимный тип ) при создании нового экземпляра класса. В случае экземпляра класса Person не все экземпляры могут петь. Эта функция используется тогда:

class Person { def tell { println ( " Human " ) } //еще методы }        val singingPerson = новый Person с Singer singingPerson . sing      

В ржавчине

Rust широко использует миксины через черты . Черты, как и в Scala, позволяют пользователям реализовывать поведения для определенного типа. Они также используются для дженериков и динамической диспетчеризации , позволяя типам, реализующим черту, использоваться взаимозаменяемо статически или динамически во время выполнения. [28]

// Позволяет типам «говорить» черта Speak { fn speak ();   // Rust позволяет разработчикам определять реализации по умолчанию для функций, определенных в трейтах fn greet () { println! ( "Привет!" ) } }  структура  Собака ;impl Speak for Dog { fn speak () { println! ( "Гав-гав" ); } }      структура  Робот ;impl Speak for Robot { fn speak () { println! ( "Бип-бип-буп-буп" ); }      // Здесь мы переопределяем определение Speak::greet для Robot fn greet () { println! ( "Robot says howdy!" ) } }  

В Свифте

Миксин можно реализовать в Swift, используя языковую функцию, которая называется «Реализация по умолчанию» в расширении протокола.

протокол  ErrorDisplayable  {  ошибка функции ( сообщение : строка )}расширение  ErrorDisplayable  {  ошибка функции ( сообщение : строка )  { // Сделайте то, что нужно, чтобы показать ошибку //... печать ( сообщение ) }}структура  NetworkManager  :  ErrorDisplayable  { функция  onError ()  { ошибка ( «Проверьте подключение к Интернету». ) }}

Смотрите также

Ссылки

  1. ^ ab "Использование дополнений с Python | Linux Journal". www.linuxjournal.com . Получено 2023-05-23 .
  2. ^ ab AOL.COM, Bapopik at (3 августа 2002 г.). "Mix-Ins (мороженое Стива, Бостон, 1975)" . Получено 2023-05-23 .
  3. ^ ab "Реализация миксинов с помощью методов расширения C#". Zorched / One-Line Fix . Получено 2023-05-23 .
  4. ^ ab "Я знаю ответ (это 42): Миксины и C#". 2006-09-04. Архивировано из оригинала 2006-09-04 . Получено 2023-05-23 .
  5. ^ Boyland, John; Giuseppe Castagna (26 июня 1996 г.). "Type-Safe Compilation of Covariant Specialization: A Practical Case". В Pierre Cointe (ред.). ECOOP '96, Object-oriented Programming: 10th European Conference . Springer. стр. 16–17. ISBN 9783540614395. Получено 17 января 2014 г.
  6. ^ "Mix In". wiki.c2.com . Получено 2023-05-23 .
  7. ^ «Работа с миксинами в Ruby». 8 июля 2015 г.
  8. ^ «Повторное использование в ОО: наследование, композиция и миксины».
  9. ^ "Moving beyond mixins » Джастин Лейтгеб". Архивировано из оригинала 2015-09-25 . Получено 2015-09-16 .
  10. ^ «Наследование на основе миксинов» (PDF) .
  11. ^ Билл Вагнер. «Создание типов миксинов с использованием методов интерфейса по умолчанию». docs.microsoft.com . Получено 18.04.2022 .
  12. ^ slava (2010-01-25). "Factor/Features/The language". concatenative.org . Получено 2012-05-15 . Основные возможности языка Factor: … Система объектов с наследованием, обобщенными функциями, диспетчеризацией предикатов и миксинами
  13. ^ «Классы - MATLAB и Simulink - MathWorks India».
  14. ^ Ален Фриш (2013-06-14). "Объекты Mixin". LexiFi . Получено 2022-03-29 .
  15. ^ «Состав класса миксинов» . Федеральная политехническая школа Лозанны . Проверено 16 мая 2014 г.
  16. ^ "XOTcl - Учебник". media.wu-wien.ac.at . Получено 2023-05-23 .
  17. ^ "cpython: 2cb530243943 Lib/socketserver.py". hg.python.org . Получено 2023-05-23 .
  18. ^ «Миксины, пересылка и делегирование в JavaScript».
  19. ^ "DRY JavaScript с миксинами". Архивировано из оригинала 2015-09-21 . Получено 2015-09-16 .
  20. ^ «Методы по умолчанию (Учебники Java™ > Изучение языка Java > Интерфейсы и наследование)».
  21. ^ Миксины, дженерики и методы расширения в C#
  22. ^ "Методы расширения". flutterbyexample.com . Получено 2023-05-23 .
  23. ^ "Создание типов миксинов с использованием методов интерфейса по умолчанию | Microsoft Docs". 2020-04-13. Архивировано из оригинала 2020-04-13 . Получено 2023-05-23 .
  24. ^ Селигер, Питер (11.04.2014). "Drehtür: The-many-Talents-of-JavaScript". Drehtür . Получено 23.05.2023 .
  25. ^ Кролл, Ангус (31.05.2011). "Свежий взгляд на JavaScript Mixins". JavaScript, JavaScript.. . Получено 23.05.2023 .
  26. ^ "javascript-code-reuse-patterns/source/components/composition at master · petsel/javascript-code-reuse-patterns". GitHub . Получено 2023-05-23 .
  27. ^ "Scala на практике: черты как миксины – мотивация". 19 июля 2009 г.
  28. ^ «Черты: определение общего поведения — язык программирования Rust».

Внешние ссылки