stringtranslate.com

mezclando

En los lenguajes de programación orientados a objetos , un mixin (o mix-in ) [1] [2] [3] [4] es una clase que contiene métodos para uso de otras clases sin tener que ser la clase padre de esas otras clases. La forma en que esas otras clases obtienen acceso a los métodos del mixin depende del idioma. A veces se describe a los mixins como "incluidos" en lugar de "heredados".

Los mixins fomentan la reutilización de código y pueden usarse para evitar la ambigüedad de herencia que la herencia múltiple puede causar [5] (el " problema del diamante "), o para solucionar la falta de soporte para la herencia múltiple en un idioma. Un mixin también puede verse como una interfaz con métodos implementados . Este patrón es un ejemplo de aplicación del principio de inversión de dependencia .

Historia

Mixins apareció por primera vez en el sistema Flavors orientado a objetos de Symbolics (desarrollado por Howard Cannon), que era un enfoque de orientación a objetos utilizado en Lisp Machine Lisp . El nombre se inspiró en Steve's Ice Cream Parlour en Somerville, Massachusetts: [1] El dueño de la heladería ofrecía un sabor básico de helado (vainilla, chocolate, etc.) y lo mezclaba con una combinación de elementos adicionales (nueces, galletas, dulces, etc.) y llamó al artículo " mix-in ", su propio término de marca registrada en ese momento. [2]

Definición

Los mixins son un concepto de lenguaje que permite a un programador inyectar código en una clase . La programación mixta es un estilo de desarrollo de software , en el que se crean unidades de funcionalidad en una clase y luego se mezclan con otras clases. [6]

Una clase mixin actúa como clase principal y contiene la funcionalidad deseada. Una subclase puede entonces heredar o simplemente reutilizar esta funcionalidad, pero no como medio de especialización. Normalmente, el mixin exportará la funcionalidad deseada a una clase secundaria , sin crear una relación rígida y única "es un". Aquí radica la diferencia importante entre los conceptos de mixins y herencia , en que la clase hija aún puede heredar todas las características de la clase padre, pero no es necesario aplicar la semántica acerca de que el niño "siendo una especie de" padre.

Ventajas

  1. Proporciona un mecanismo para la herencia múltiple al permitir que una clase utilice la funcionalidad común de varias clases, pero sin la semántica compleja de la herencia múltiple. [7]
  2. Reutilización del código : los mixins son útiles cuando un programador quiere compartir funcionalidad entre diferentes clases. En lugar de repetir el mismo código una y otra vez, la funcionalidad común puede simplemente agruparse en un mixin y luego incluirse en cada clase que lo requiera. [8]
  3. Los mixins permiten la herencia y el uso solo de las características deseadas de la clase principal, no necesariamente de todas las características de la clase principal. [9]

Implementaciones

En Simula , las clases se definen en un bloque en el que los atributos, métodos e inicialización de clases se definen todos juntos; por lo tanto, todos los métodos que se pueden invocar en una clase se definen juntos y la definición de la clase está completa.

En Flavors , un mixin es una clase de la cual otra clase puede heredar definiciones y métodos de ranura. El mixin no suele tener instancias directas. Dado que un sabor puede heredar de más de otro sabor, puede heredar de uno o más mixins. Tenga en cuenta que los Flavors originales no usaban funciones genéricas.

En New Flavours (un sucesor de Flavours) y CLOS , los métodos están organizados en " funciones genéricas ". Estas funciones genéricas son funciones que se definen en múltiples casos (métodos) mediante combinaciones de métodos y envío de clases.

CLOS y Flavors permiten que los métodos mixin agreguen comportamiento a los métodos existentes: :beforey :afterdemonios, whoppers y wrappers en Flavors. CLOS agregó :aroundmétodos y la capacidad de llamar a métodos sombreados a través de CALL-NEXT-METHOD. Entonces, por ejemplo, un stream-lock-mixin puede agregar bloqueo alrededor de los métodos existentes de una clase de flujo. En Flavors uno escribiría un envoltorio o un whopper y en CLOS uno usaría un :aroundmétodo. Tanto CLOS como Flavors permiten la reutilización calculada mediante combinaciones de métodos. :before, :aftery :aroundlos métodos son una característica de la combinación de métodos estándar. Se proporcionan otras combinaciones de métodos.

Un ejemplo es la +combinación de métodos, donde los valores resultantes de cada uno de los métodos aplicables de una función genérica se suman aritméticamente para calcular el valor de retorno. Esto se utiliza, por ejemplo, con el border-mixin para objetos gráficos. Un objeto gráfico puede tener una función de ancho genérica. El border-mixin agregaría un borde alrededor de un objeto y tiene un método para calcular su ancho. Una nueva clase bordered-button(que es a la vez un objeto gráfico y utiliza el bordermixin) calcularía su ancho llamando a todos los métodos de ancho aplicables, a través de la +combinación de métodos. Todos los valores de retorno se agregan y crean el ancho combinado del objeto.

En un artículo de OOPSLA 90, [10] Gilad Bracha y William Cook reinterpretan diferentes mecanismos de herencia encontrados en Smalltalk, Beta y CLOS como formas especiales de herencia mixin.

Lenguajes de programación que utilizan mixins.

Además de Flavors y CLOS (una parte de Common Lisp ), algunos lenguajes que usan mixins son:

Algunos lenguajes no admiten mixins a nivel de lenguaje, pero pueden imitarlos fácilmente copiando métodos de un objeto a otro en tiempo de ejecución, "tomando prestados" los métodos del mixin. Esto también es posible con lenguajes de tipo estático , pero requiere construir un nuevo objeto con el conjunto extendido de métodos.

Otros lenguajes que no soportan mixins pueden soportarlos de forma indirecta a través de otras construcciones del lenguaje. Por ejemplo, Visual Basic .NET y C# admiten la adición de métodos de extensión en las interfaces, lo que significa que cualquier clase que implemente una interfaz con métodos de extensión definidos tendrá los métodos de extensión disponibles como pseudomiembros.

Ejemplos

En ceceo común

Common Lisp proporciona mixins en CLOS (Common Lisp Object System) similares a Flavors.

object-widthes una función genérica con un argumento que utiliza la +combinación de métodos. Esta combinación determina que se llamarán todos los métodos aplicables para una función genérica y se agregarán los resultados.

( ancho de objeto defgenérico ( objeto ) ( : combinación de métodos + ))    

buttones una clase con un espacio para el texto del botón.

( botón defclass () (( texto :initform "haz clic en mí" )))     

Existe un método para objetos de clase botón que calcula el ancho en función de la longitud del texto del botón. +es el calificador de método para la combinación de métodos del mismo nombre.

( defmethod ancho de objeto + (( botón de objeto )) ( * 10 ( longitud ( texto de objeto de valor de ranura ))))          

Una border-mixinclase. El nombre es sólo una convención. No hay superclases ni espacios.

( defclass borde-mixin () ())   

Existe un método que calcula el ancho del borde. Aquí son solo 4.

( defmethod ancho de objeto + (( mezcla de borde de objeto )) 4 )     

bordered-buttones una clase que hereda de ambos border-mixiny button.

( defclass botón con borde ( botón de mezcla de borde ) ())    

Ahora podemos calcular el ancho de un botón. Llamar object-widthcalcula 80. El resultado es el resultado del único método aplicable: el método object-widthde la clase button.

? ( ancho de objeto ( botón ' crear instancia ' )) 80   

También podemos calcular el ancho de a bordered-button. Llamar object-widthcalcula 84. El resultado es la suma de los resultados de los dos métodos aplicables: el método object-widthde la clase buttony el método object-widthde la clase border-mixin.

? ( ancho de objeto ( crear instancia 'botón con borde )) 84   

En pitón

En Python , un ejemplo del concepto mixin se encuentra en el SocketServermódulo [17] que tiene tanto una UDPServerclase como una TCPServerclase. Actúan como servidores para servidores de socket UDP y TCP , respectivamente. Además, hay dos clases de mixin: ForkingMixIny ThreadingMixIn. Normalmente, todas las conexiones nuevas se manejan dentro del mismo proceso. Ampliando TCPServercon lo ThreadingMixInsiguiente:

clase  ThreadingTCPServer ( ThreadingMixIn ,  TCPServer ):  pasar

la ThreadingMixInclase agrega funcionalidad al servidor TCP de modo que cada nueva conexión crea un nuevo hilo . Usando el mismo método, se ThreadingUDPServerpuede crear un sin tener que duplicar el código en ThreadingMixIn. Alternativamente, usar ForkingMixInharía que el proceso se bifurque para cada nueva conexión. Claramente, la funcionalidad para crear un nuevo hilo o bifurcar un proceso no es muy útil como clase independiente.

En este ejemplo de uso, los mixins proporcionan una funcionalidad subyacente alternativa sin afectar la funcionalidad como servidor de socket.

en rubí

La mayor parte del mundo Ruby se basa en mixins a través de Modules. El concepto de mixins se implementa en Ruby mediante la palabra clave includea la que le pasamos como parámetro el nombre del módulo .

Ejemplo:

clase Estudiante incluye Comparable # La clase Estudiante hereda el módulo Comparable usando la palabra clave 'incluir' attr_accessor :nombre , :puntuación        def inicializar ( nombre , puntuación ) @nombre = nombre @puntuación = final de la puntuación          # Incluir el módulo Comparable requiere que la clase implementadora defina el operador de comparación <=> # Aquí está el operador de comparación. Comparamos 2 instancias de estudiantes en función de sus puntuaciones.  def <=> ( otro ) @score <=> otro . final de la puntuación      # Esto es lo bueno: tengo acceso a <, <=, >,>= y otros métodos de la Interfaz Comparable de forma gratuita. fins1 = Estudiante . nuevo ( "Peter" , 100 ) s2 = Estudiante . nuevo ( "Jasón" , 90 )      s1 > s2 #verdadero s1 <= s2 #falso      

En JavaScript

El literal de objeto y extendel enfoque

Es técnicamente posible agregar comportamiento a un objeto vinculando funciones a claves en el objeto. Sin embargo, esta falta de separación entre estado y comportamiento tiene inconvenientes:

  1. Entremezcla propiedades del dominio del modelo con las del dominio de implementación.
  2. No compartir comportamientos comunes. Los metaobjetos resuelven este problema separando las propiedades específicas del dominio de los objetos de sus propiedades específicas del comportamiento. [18]

Se utiliza una función de extensión para mezclar el comportamiento en: [19]

'uso estricto' ;const Halfling = function ( fName , lName ) { this . nombre = fNombre ; este . apellido = lNombre ; };            const mixin = { nombre completo () { devuelve esto . nombre + '' + esto . apellido ; }, cambiar el nombre ( primero , último ) { este . primerNombre = primero ; este . apellido = apellido ; devolver esto ; } };                        // Una función de extensión const extend = ( obj , mixin ) => { Object . teclas ( mezcla ). forEach ( tecla => obj [ tecla ] = mixin [ tecla ]); objeto de retorno ; };             const sam = nuevo Halfling ( 'Sam' , 'Loawry' ); const frodo = nuevo Halfling ( 'Freeda' , 'Baggs' );          // Mezclando los otros métodos extend ( Halfling . prototipo , mixin ); consola . iniciar sesión ( sam . nombre completo ()); // Consola de Sam Loawry . log ( frodo . nombre completo ()); // Freeda Baggs  sam . cambiar nombre ( 'Samwise' , 'Gamgee' ); frodo . cambiar nombre ( 'Frodo' , 'Bolsón' );  consola . iniciar sesión ( sam . nombre completo ()); // Consola Samwise Gamgee . log ( frodo . nombre completo ()); // Frodo Bolsón  

Mezclando con el uso de Object.assign()

'uso estricto' ;// Creando un objeto const obj1 = { nombre : 'Marco Aurelio' , ciudad : 'Roma' , nacimiento : '121-04-26' };         // Mixin 1 const mix1 = { toString () { return ` ${ this . nombre } nació en ${ this . ciudad } en ${ esto . nacido } ` ; }, edad () { año constante = nueva fecha (). getAñoCompleto (); const nacido = nueva fecha ( este . nacido ). getAñoCompleto (); año de retorno nacido ; } }; // Mixin 2 const mix2 = { toString () { return ` ${ esto . nombre } - ${ esto . ciudad } - ${ esto . nacido } ` ; } };                                 // Agregar los métodos de mixins al objeto usando Object.assign() Object . asignar ( obj1 , mezclar1 , mezclar2 );  consola . iniciar sesión ( obj1 . toString ()); // Marco Aurelio - Roma - 121-04-26 consola . log ( `Su edad es ${ obj1 . age () } a partir de hoy` ); // Su edad es 1897 a día de hoy.  

El enfoque Flight-Mixin basado en funciones puras y delegación

Aunque el enfoque descrito en primer lugar está muy extendido, el siguiente se acerca más a lo que ofrece fundamentalmente el núcleo del lenguaje JavaScript: la delegación .

Dos patrones basados ​​en objetos de función ya funcionan sin la necesidad de la implementación de extend.

'uso estricto' ;// Implementación const EnumerableFirstLast = ( function () { // patrón de módulo basado en funciones. const first = function () { return this [ 0 ]; }, last = function () { return this [ this . length - 1 ]; } ; return function () { // Mecánica de Flight-Mixin basada en funciones... this.first = first ; // ... refiriéndose a... this . last = last ; //... código compartido. } ; } ());                                       // Aplicación - delegación explícita: // aplicando el [primer] y el [último] comportamiento enumerable en el [prototipo] de [Array]. EnumerableFirstLast . llamar ( matriz . prototipo );// Ahora puedes hacer: const a = [ 1 , 2 , 3 ]; a . primero (); // 1 a . último (); // 3       

En otros idiomas

En el lenguaje de contenido web Curl , se utiliza la herencia múltiple ya que las clases sin instancias pueden implementar métodos. Los mixins comunes incluyen todos ControlUIlos mensajes personalizables que heredan de SkinnableControlUI, objetos delegados de interfaz de usuario que requieren menús desplegables heredados de StandardBaseDropdownUI y clases mixin con nombres explícitos como FontGraphicMixiny FontVisualMixinclass NumericAxisMixin-of. La versión 7.0 agregó acceso a la biblioteca para que los mixins no necesiten estar en el mismo paquete ni ser un resumen público. Los constructores de curl son fábricas que facilitan el uso de herencia múltiple sin una declaración explícita de interfaces o mixins. [ cita necesaria ]

Interfaces y rasgos

Java 8 introduce una nueva característica en forma de métodos predeterminados para interfaces. [20] Básicamente, permite definir un método en una interfaz con la aplicación en el escenario en el que se debe agregar un nuevo método a una interfaz después de realizar la configuración de programación de la clase de interfaz. Agregar una nueva función a la interfaz significa implementar el método en cada clase que usa la interfaz. Los métodos predeterminados ayudan en este caso, ya que pueden introducirse en una interfaz en cualquier momento y tienen una estructura implementada que luego utilizan las clases asociadas. Por lo tanto, los métodos predeterminados agregan la capacidad de aplicar el concepto mixin en Java.

Las interfaces combinadas con la programación orientada a aspectos también pueden producir mixins completos en lenguajes que admitan dichas características, como C# o Java. Además, mediante el uso del patrón de interfaz de marcador , la programación genérica y los métodos de extensión, C# 3.0 tiene la capacidad de imitar mixins. Con Dart 2.7 y C# 3.0 llegó la introducción de métodos de extensión que se pueden aplicar, no sólo a las clases, sino también a las interfaces. Los métodos de extensión proporcionan funcionalidad adicional en una clase existente sin modificar la clase. Entonces es posible crear una clase auxiliar estática para una funcionalidad específica que define los métodos de extensión. Debido a que las clases implementan la interfaz (incluso si la interfaz real no contiene ningún método o propiedad para implementar), también recogerá todos los métodos de extensión. [3] [4] [21] C# 8.0 agrega la característica de métodos de interfaz predeterminados. [22] [23]

ECMAScript (en la mayoría de los casos implementado como JavaScript) no necesita imitar la composición de objetos copiando campos paso a paso de un objeto a otro. De forma nativa [24] admite la composición de objetos basada en Trait y mixin [25] [26] a través de objetos de función que implementan un comportamiento adicional y luego se delegan a través callde applyobjetos que necesitan dicha nueva funcionalidad.

en escala

Scala tiene un rico sistema de tipos y los rasgos son parte de él y ayudan a implementar el comportamiento de mezcla. Como su nombre lo revela, los rasgos se usan generalmente para representar una característica o aspecto distintivo que normalmente es ortogonal a la responsabilidad de un tipo concreto o al menos de una determinada instancia. [27] Por ejemplo, la capacidad de cantar se modela como una característica ortogonal: podría aplicarse a pájaros, personas, etc.

rasgo Singer { def sing { println ( " cantando … " ) } //más métodos }       clase pájaro extiende cantante   

Aquí, Bird ha mezclado todos los métodos del rasgo en su propia definición como si la clase Bird hubiera definido el método sing() por sí sola.

Como extendstambién se usa para heredar de una superclase, en el caso de un rasgo extendsse usa si no se hereda ninguna superclase y solo para mezclar en el primer rasgo. Todos los rasgos siguientes se combinan con el uso de palabras clave with.

clase Persona clase Actor extiende Persona con Cantante clase Actor extiende Cantante con Intérprete           

Scala permite mezclar un rasgo (crear un tipo anónimo ) al crear una nueva instancia de una clase. En el caso de una instancia de clase Persona, no todas las instancias pueden cantar. Esta característica se utiliza entonces:

clase Persona { def tell { println ( " Humano " ) } //más métodos }        val cantandoPersona = nueva Persona con Cantante cantandoPersona . cantar      

En óxido

Rust hace un uso extensivo de mixins a través de rasgos . Los rasgos, como en Scala, permiten a los usuarios implementar comportamientos para un tipo definido. También se utilizan para envíos genéricos y dinámicos , que permiten que tipos con las mismas características se utilicen indistintamente de forma estática o dinámica en tiempo de ejecución, respectivamente. [28]

// Permite que los tipos "hablen" rasgo Hablar { fn hablar ();   // Rust permite a los implementadores definir implementaciones predeterminadas para funciones definidas en rasgos fn greet () { println! ( "¡Hola!" ) } }  estructura  Perro ;impl Hablar por perro { fn hablar () { println! ( "Guau guau" ); } }       robot de estructura ;impl Hablar por Robot { fn hablar () { println! ( "Bip bip boop boop" ); }      // Aquí anulamos la definición de Speak::greet para Robot fn greet () { println! ( " ¡ El robot dice hola!" ) } }  

En rápido

Mixin se puede lograr en Swift mediante el uso de una función de lenguaje llamada Implementación predeterminada en la extensión del protocolo.

protocolo  ErrorDisplayable  {  error de función ( mensaje : cadena )}extensión  ErrorDisplayable  {  error de función ( mensaje : cadena )  { //Haz lo que sea necesario para mostrar un error //... imprimir ( mensaje ) }}estructura  NetworkManager  :  ErrorDisplayable  { función  onError ()  { error ( "Por favor verifique su conexión a Internet." ) }}

Ver también

Referencias

  1. ^ ab "Uso de combinaciones con Python | Linux Journal". www.linuxjournal.com . Consultado el 23 de mayo de 2023 .
  2. ^ ab AOL.COM, Bapopik en (3 de agosto de 2002). "Mix-Ins (helado de Steve, Boston, 1975)" . Consultado el 23 de mayo de 2023 .
  3. ^ ab "Implementación de Mixins con métodos de extensión de C#". Zorched / Solución de una línea . Consultado el 23 de mayo de 2023 .
  4. ^ ab "Sé la respuesta (es 42): Mixins y C#". 2006-09-04. Archivado desde el original el 4 de septiembre de 2006 . Consultado el 23 de mayo de 2023 .
  5. ^ Boyland, John; Giuseppe Castagna (26 de junio de 1996). "Compilación de especialización covariante con tipos seguros: un caso práctico". En Pierre Cointe (ed.). ECOOP '96, Programación orientada a objetos: Décima Conferencia Europea . Saltador. págs. 16-17. ISBN 9783540614395. Consultado el 17 de enero de 2014 .
  6. ^ "Mezclar". wiki.c2.com . Consultado el 23 de mayo de 2023 .
  7. ^ "Trabajar con Mixins en Ruby". 8 de julio de 2015.
  8. ^ "Reutilización en OO: herencia, composición y mezclas".
  9. ^ "Más allá de los mixins» Justin Leitgeb ". Archivado desde el original el 25 de septiembre de 2015 . Consultado el 16 de septiembre de 2015 .
  10. ^ "Herencia basada en Mixin" (PDF) .
  11. ^ Bill Wagner. "Cree tipos mixin utilizando métodos de interfaz predeterminados". docs.microsoft.com . Consultado el 18 de abril de 2022 .
  12. ^ eslava (25 de enero de 2010). "Factor/Características/El idioma". concatenative.org . Consultado el 15 de mayo de 2012 . Principales características del lenguaje de Factor: … Sistema de objetos con herencia, funciones genéricas, despacho de predicados y mixins.
  13. ^ "Clases - MATLAB y Simulink - MathWorks India".
  14. ^ Alain Frisch (14 de junio de 2013). "Mezclar objetos". LexiFi . Consultado el 29 de marzo de 2022 .
  15. ^ "Composición de clases Mixin". Escuela Politécnica Federal de Lausana . Consultado el 16 de mayo de 2014 .
  16. ^ "XOTcl - Tutorial". media.wu-wien.ac.at . Consultado el 23 de mayo de 2023 .
  17. ^ "cpython: 2cb530243943 Lib/socketserver.py". hg.python.org . Consultado el 23 de mayo de 2023 .
  18. ^ "Mixins, reenvío y delegación en JavaScript".
  19. ^ "JavaScript SECO con mixins". Archivado desde el original el 21 de septiembre de 2015 . Consultado el 16 de septiembre de 2015 .
  20. ^ "Métodos predeterminados (Tutoriales de Java™ > Aprendizaje del lenguaje Java > Interfaces y herencia)".
  21. ^ Mixins, genéricos y métodos de extensión en C#
  22. ^ "Métodos de extensión". flutterbyexample.com . Consultado el 23 de mayo de 2023 .
  23. ^ "Cree tipos mixin utilizando métodos de interfaz predeterminados | Microsoft Docs". 2020-04-13. Archivado desde el original el 13 de abril de 2020 . Consultado el 23 de mayo de 2023 .
  24. ^ Seliger, Peter (11 de abril de 2014). "Drehtür: Los-muchos-talentos-de-JavaScript". Drehtür . Consultado el 23 de mayo de 2023 .
  25. ^ Croll, Angus (31 de mayo de 2011). "Una nueva mirada a los Mixins de JavaScript". JavaScript, JavaScript ... Consultado el 23 de mayo de 2023 .
  26. ^ "javascript-code-reuse-patterns/source/components/composition en master · petsel/javascript-code-reuse-patterns". GitHub . Consultado el 23 de mayo de 2023 .
  27. ^ "Scala en la práctica: rasgos como mixins - motivación". 19 de julio de 2009.
  28. ^ "Rasgos: definición de comportamiento compartido: el lenguaje de programación Rust".

enlaces externos