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 que los usen 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 lenguaje. A veces se describe a los mixins como "incluidos" en lugar de "heredados".

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

Historia

Los mixins aparecieron por primera vez en el sistema Flavors orientado a objetos de Symbolics (desarrollado por Howard Cannon), que era un enfoque de la orientación a objetos utilizado en Lisp Machine Lisp . El nombre se inspiró en la heladería Steve's Ice Cream Parlor 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, dulce de azúcar, etc.) y llamaba al elemento " mix-in ", su propio término registrado 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 mixin 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 la clase padre, que contiene la funcionalidad deseada. Una subclase puede heredar o simplemente reutilizar esta funcionalidad, pero no como un medio de especialización. Normalmente, el mixin exportará la funcionalidad deseada a una clase hija , sin crear una relación rígida y única de "es un". Aquí radica la diferencia importante entre los conceptos de mixins y herencia , en que la clase hija todavía puede heredar todas las características de la clase padre, pero no es necesario aplicar la semántica sobre que la hija "es un tipo de" la clase padre.

Ventajas

  1. Proporciona un mecanismo para la herencia múltiple al permitir que una clase utilice la funcionalidad común de múltiples clases, pero sin la semántica compleja de la herencia múltiple. [7]
  2. Reutilización de 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 la requiera. [8]
  3. Los mixins permiten la herencia y el uso solo de las características deseadas de la clase padre, no necesariamente todas las características de la clase padre. [9]

Implementaciones

En Simula , las clases se definen en un bloque en el que los atributos, métodos y la inicialización de la clase se definen 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 que otra clase puede heredar definiciones y métodos de slot. El mixin normalmente no tiene instancias directas. Dado que un Flavor puede heredar de más de otro Flavor, puede heredar de uno o más mixins. Tenga en cuenta que los Flavors originales no usaban funciones genéricas.

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

CLOS y Flavors permiten que los métodos mixin agreguen comportamiento a los métodos existentes: :beforey :afterdaemons, whoppers y wrappers en Flavors. CLOS agregó :aroundmétodos y la capacidad de llamar a métodos shadowed a través de CALL-NEXT-METHOD. Entonces, por ejemplo, un stream-lock-mixin puede agregar bloqueos alrededor de los métodos existentes de una clase stream. En Flavors uno escribiría un wrapper o un whopper y en CLOS uno usaría un :aroundmétodo. Tanto CLOS como Flavors permiten la reutilización computada a través de 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 que calcula 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. Se suman todos los valores de retorno y se crea 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 una 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" así los métodos del mixin. Esto también es posible con lenguajes de tipado estático , pero requiere construir un nuevo objeto con el conjunto extendido de métodos.

Otros lenguajes que no admiten mixins pueden admitirlos de forma indirecta a través de otras construcciones del lenguaje. Por ejemplo, Visual Basic .NET y C# admiten la incorporación de métodos de extensión en 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 Common Lisp

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 sumarán los resultados.

( defgeneric object-width ( objeto ) ( :combinación-de-métodos + ))    

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

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

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

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

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

( defclass borde-mix () ())   

Hay un método para calcular el ancho del borde. Aquí es solo 4.

( defmethod objeto-ancho + (( objeto borde-mix )) 4 )     

bordered-buttones una clase que hereda tanto de border-mixincomo button.

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

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

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

También podemos calcular el ancho de un bordered-button. Al llamar object-widthse calcula 84. El resultado es la suma de los resultados de los dos métodos aplicables: el método object-widthpara la clase buttony el método object-widthpara la clase border-mixin.

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

En Python

En Python , un ejemplo del concepto de mixin se encuentra en el SocketServermódulo [18] , que tiene tanto una UDPServerclase como una TCPServerclase. Actúan como servidores para servidores de sockets UDP y TCP , respectivamente. Además, hay dos clases de mixin: ForkingMixIny ThreadingMixIn. Normalmente, todas las conexiones nuevas se manejan dentro del mismo proceso. Al extender 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 . Con el mismo método, ThreadingUDPServerse puede crear un sin tener que duplicar el código en ThreadingMixIn. Alternativamente, el uso de ForkingMixInharía que el proceso se bifurcara para cada nueva conexión. Claramente, la funcionalidad para crear un nuevo hilo o bifurcar un proceso no es demasiado útil como una 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 pasamos el nombre del módulo como parámetro .

Ejemplo:

clase Estudiante incluye Comparable # La clase Estudiante hereda el módulo Comparable usando la palabra clave 'include' attr_accessor :name , :score        def initialize ( nombre , puntuación ) @nombre = nombre @puntuación = puntuación fin          # La inclusión del 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 . puntuación fin      # Aquí viene la parte buena: obtengo acceso a <, <=, >,>= y otros métodos de la Interfaz Comparable de forma gratuita. fins1 = Estudiante . nuevo ( "Peter" , 100 ) s2 = Estudiante . nuevo ( "Jason" , 90 )      s1 > s2 #verdadero s1 <= s2 #falso      

En JavaScript

El objeto-literal y extendel enfoque

Técnicamente es posible agregarle comportamiento a un objeto vinculando funciones a claves del objeto. Sin embargo, esta falta de separación entre estado y comportamiento tiene desventajas:

  1. Mezcla propiedades del dominio del modelo con las del dominio de implementación.
  2. No se comparte el comportamiento común. Los metaobjetos resuelven este problema separando las propiedades específicas del dominio de los objetos de sus propiedades específicas del comportamiento. [19]

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

'uso estricto' ;const Halfling = function ( fName , lName ) { this .firstName = fName ; this .apellido = lName ; } ;            const mixin = { fullName ( ) { devuelve este.firstName + ' ' + este.apellido ; } , rename ( nombre , apellido ) { este.firstName = nombre ; este.apellido = apellido ; devuelve este ; } } ;                        // Una función de extensión const extend = ( obj , mixin ) => { Object . keys ( mixin ). forEach ( key => obj [ key ] = mixin [ key ]); return obj ; };             const sam = nuevo Halfling ( 'Sam' , 'Loawry' ); const frodo = nuevo Halfling ( 'Freeda' , 'Baggs' );          // Mezclando los otros métodos extend ( Halfling . prototipo , mixin ); console.log ( sam.nombrecompleto ( ) ) ; // Sam Loawry console.log ( frodo.nombrecompleto () ) ; // Freeda Baggs  sam . rename ( 'Samwise' , 'Gamgi' ); frodo . rename ( 'Frodo' , 'Bolsón' );  console.log ( sam.fullName ( ) ); // Samwise Gamgee console.log ( frodo.fullName ( ) ) ; // Frodo Baggins  

Combinación 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 . name } nació en ${ this . city } en ${ this . born } ` ; }, edad () { const año = new Date (). getFullYear (); const nacido = new Date ( this . born ). getFullYear (); return año - nacido ; } }; // Mixin 2 const mix2 = { toString () { return ` ${ this . name } - ${ this . city } - ${ this . born } ` ; } };                                 // Agregar los métodos de mixins al objeto usando Object.assign() Object .assign ( obj1 , mix1 , mix2 );  console.log ( obj1.toString ()); // Marco Aurelio - Roma - 121-04-26 console.log ( ` Su edad es ${ obj1.age () } a día de hoy` ) ; //Su edad es 1897 a día de hoy  

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

Aunque el primer enfoque descrito es el más 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 hacen el trabajo sin necesidad de una implementación de terceros 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 basada en funciones de Flight-Mixin ... this . first = first ; // ... haciendo referencia a ... this . last = last ; // ... código compartido. }; }());                                       // Aplicación - delegación explícita: // aplicando el comportamiento enumerable [primero] y [último] al [prototipo] de [Array]. EnumerableFirstLast . call ( Array . prototipo );// Ahora puedes hacer: const a = [ 1 , 2 , 3 ]; a . first (); // 1 a . last (); // 3       

En otros idiomas

En el lenguaje de contenido web Curl , se utiliza herencia múltiple, ya que las clases sin instancias pueden implementar métodos. Los mixins comunes incluyen todos ControlUIlos s que se pueden personalizar y que heredan de SkinnableControlUI, objetos delegados de interfaz de usuario que requieren menús desplegables que heredan de StandardBaseDropdownUI y clases de mixins nombradas explícitamente como FontGraphicMixin, FontVisualMixiny NumericAxisMixin-ofclass. La versión 7.0 agregó acceso a bibliotecas para que los mixins no necesiten estar en el mismo paquete o ser abstractos públicos. 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 requerida ]

Interfaces y rasgos

Java 8 introduce una nueva característica en forma de métodos predeterminados para interfaces. [21] 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 que se haya realizado 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 se pueden introducir en una interfaz en cualquier momento y tienen una estructura implementada que luego es utilizada por las clases asociadas. Por lo tanto, los métodos predeterminados agregan la capacidad de aplicar el concepto de mixin en Java.

Las interfaces combinadas con la programación orientada a aspectos también pueden producir mixins completos en lenguajes que admiten 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 solo a clases, sino también a interfaces. Los métodos de extensión proporcionan funcionalidad adicional en una clase existente sin modificar la clase. Luego, se hace 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] [22] C# 8.0 agrega la característica de métodos de interfaz predeterminados. [23] [24]

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 [25] admite la composición de objetos basada en Trait y mixin [26] [27] a través de objetos de función que implementan un comportamiento adicional y luego se delegan a través de callo applyhacia objetos que necesitan esa nueva funcionalidad.

En Scala

Scala tiene un sistema de tipos rico y los rasgos son una parte de él que ayuda a implementar el comportamiento de mixin. Como su nombre lo revela, los rasgos se utilizan 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. [28] Por ejemplo, la capacidad de cantar se modela como una característica ortogonal: podría aplicarse a pájaros, personas, etc.

rasgo Cantante { def sing { println ( " cantando … " ) } //más métodos }       La clase Pájaro extiende a Singer   

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 que extendsse use un rasgo si no se hereda ninguna superclase y solo para mezclar en el primer rasgo. Todos los rasgos siguientes se mezclan usando la palabra 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 la clase Person, no todas las instancias pueden cantar. Esta característica se utiliza entonces:

clase Persona { def tell { println ( " Humano " ) } //más métodos }        val singerPerson = new Persona con Singer singerPerson . sing      

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 genéricos y despacho dinámico , lo que permite que los tipos que implementan un rasgo se utilicen indistintamente de forma estática o dinámica en tiempo de ejecución. [29]

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

En rápido

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

Error de protocolo  Desplegable  {  error de función ( mensaje : cadena )}extensión  ErrorDisplayable  { func  error ( 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." ) }}

Véase también

Referencias

  1. ^ ab "Uso de Mix-ins con Python | Linux Journal". www.linuxjournal.com . Consultado el 23 de mayo de 2023 .
  2. ^ de AOL.COM, Bapopik at (3 de agosto de 2002). "Mix-Ins (Steve's ice cream, Boston, 1975)" . Consultado el 23 de mayo de 2023 .
  3. ^ ab "Implementación de mixins con métodos de extensión de C#". Zorched / One-Line Fix . Consultado el 23 de mayo de 2023 .
  4. ^ ab "Sé la respuesta (es 42): Mixins y C#". 4 de septiembre de 2006. 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 seguridad de tipos: un caso práctico". En Pierre Cointe (ed.). ECOOP '96, Programación orientada a objetos: 10.ª Conferencia Europea . Springer. págs. 16-17. ISBN. 9783540614395. Recuperado 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 mixins".
  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 mixina" (PDF) .
  11. ^ Bill Wagner. "Crear tipos de mixin utilizando métodos de interfaz predeterminados". docs.microsoft.com . Consultado el 18 de abril de 2022 .
  12. ^ "ET: La herencia". www.eiffel.org . 2024-06-03 . Consultado el 2024-11-05 .
  13. ^ slava (25 de enero de 2010). "Factor/Características/El lenguaje". concatenative.org . Consultado el 15 de mayo de 2012. Principales características del lenguaje de Factor: … Sistema de objetos con herencia, funciones genéricas, envío de predicados y mixins
  14. ^ "Clases - MATLAB y Simulink - MathWorks India".
  15. ^ Alain Frisch (14 de junio de 2013). «Objetos Mixin». LexiFi . Consultado el 29 de marzo de 2022 .
  16. ^ "Composición de clases Mixin". Escuela Politécnica Federal de Lausana . Consultado el 16 de mayo de 2014 .
  17. ^ "XOTcl - Tutorial". media.wu-wien.ac.at . Consultado el 23 de mayo de 2023 .
  18. ^ "cpython: 2cb530243943 Lib/socketserver.py". hg.python.org . Consultado el 23 de mayo de 2023 .
  19. ^ "Mixins, reenvío y delegación en JavaScript".
  20. ^ "JavaScript DRY con mixins". Archivado desde el original el 21 de septiembre de 2015. Consultado el 16 de septiembre de 2015 .
  21. ^ "Métodos predeterminados (Tutoriales de Java™ > Aprendiendo el lenguaje Java > Interfaces y herencia)".
  22. ^ Mixins, genéricos y métodos de extensión en C#
  23. ^ "Métodos de extensión". flutterbyexample.com . Consultado el 23 de mayo de 2023 .
  24. ^ "Crear tipos de mixin usando métodos de interfaz predeterminados | Microsoft Docs". 13 de abril de 2020. Archivado desde el original el 13 de abril de 2020. Consultado el 23 de mayo de 2023 .
  25. ^ Seliger, Peter (11 de abril de 2014). "Drehtür: Los múltiples talentos de JavaScript". Drehtür . Consultado el 23 de mayo de 2023 .
  26. ^ Croll, Angus (31 de mayo de 2011). "Una nueva mirada a los mixins de JavaScript". JavaScript, JavaScript... . Consultado el 23 de mayo de 2023 .
  27. ^ "patrones-de-reutilización-de-código-javascript/fuente/componentes/composición en master · petsel/patrones-de-reutilización-de-código-javascript". GitHub . Consultado el 23 de mayo de 2023 .
  28. ^ "Scala en la práctica: rasgos como mixins – motivación". 19 de julio de 2009.
  29. ^ "Rasgos: Definición del comportamiento compartido - el lenguaje de programación Rust".

Enlaces externos