stringtranslate.com

Reenvío (programación orientada a objetos)

En la programación orientada a objetos , el reenvío significa que el uso de un miembro de un objeto (ya sea una propiedad o un método ) da como resultado el uso del miembro correspondiente de un objeto diferente: el uso se reenvía a otro objeto. El reenvío se utiliza en varios patrones de diseño , donde algunos miembros se reenvían a otro objeto, mientras que otros son manejados por el objeto utilizado directamente. El objeto de reenvío se denomina frecuentemente objeto contenedor y los miembros de reenvío explícitos se denominan funciones contenedoras .

Delegación

A menudo se confunde el reenvío con la delegación ; formalmente, son conceptos complementarios. En ambos casos, hay dos objetos, y el primer objeto (envío, contenedor) utiliza el segundo objeto (recepción, envoltura), por ejemplo, para llamar a un método. Se diferencian en lo que selfse refiere al objeto receptor (formalmente, en el entorno de evaluación del método sobre el objeto receptor): en delegación se refiere al objeto emisor, mientras que en reenvío se refiere al objeto receptor. Tenga en cuenta que selfa menudo se usa implícitamente como parte del envío dinámico (resolución de método: a qué función se refiere el nombre de un método).

La diferencia entre reenvío y delegación es la vinculación del parámetro self en el wrappee cuando se llama a través del contenedor. Con la delegación, el parámetro self está vinculado al contenedor, con el reenvío está vinculado al wrappee. ... El reenvío es una forma de reenvío automático de mensajes; La delegación es una forma de herencia con vinculación del padre (superclase) en tiempo de ejecución, en lugar de en tiempo de compilación/enlace como ocurre con la herencia "normal". [1]

Por ejemplo, dado el siguiente código:

// Remitente void n () { print ( "n1" ); }   // Receptor void m () { print ( "m2, " ); norte (); }    vacío n () { imprimir ( "n2" ); }   

bajo delegación esto generarám2,n1porque n()se evalúa en el contexto del objeto original (de envío), mientras que en el reenvío esto generarám2,n2porque n()se evalúa en el contexto del objeto receptor. [1]

En el uso informal, el reenvío a menudo se denomina "delegación" o se considera una forma de delegación, pero en un uso cuidadoso se distinguen claramente por lo que se selfrefiere. Mientras que la delegación es análoga a la herencia , permitiendo la reutilización del comportamiento (y concretamente la reutilización del código ) sin cambiar el contexto de evaluación, el reenvío es análogo a la composición , ya que la ejecución depende sólo del objeto receptor (miembro), no del objeto emisor (original). En ambos casos, la reutilización es dinámica, es decir, determinada en tiempo de ejecución (en función del objeto al que se delega o reenvía el uso), en lugar de estática, es decir, determinada en tiempo de compilación/enlace (en función de la clase de la que se hereda). Al igual que la herencia, la delegación permite que el objeto emisor modifique el comportamiento original, pero es susceptible a problemas análogos a los de la clase base frágil ; mientras que el reenvío proporciona una encapsulación más fuerte y evita estos problemas; ver composición sobre herencia . [1]

Ejemplos

Un ejemplo simple de reenvío explícito en Java: una instancia de Bllamadas de reenvío al foométodo de su acampo:

clase  B { A una ; T foo () { devolver a . foo (); } }         

Tenga en cuenta que al ejecutar a.foo(), el thisobjeto es a(un subtipo de A), no el objeto original (una instancia de B). Además, ano es necesario que sea una instancia de A: puede ser una instancia de un subtipo. De hecho, Ani siquiera es necesario que sea una clase: puede ser una interfaz/ protocolo .

En contraste con la herencia, en la que foose define en una superclase A(que debe ser una clase, no una interfaz), y cuando se llama a una instancia de una subclase B, utiliza el código definido en A, pero el thisobjeto sigue siendo una instancia de B:

clase  A { T foo () { /* ... */ }; }      la clase  B extiende A { }   

En este ejemplo de Python, la clase Breenvía el foométodo y la xpropiedad al objeto en su acampo: usarlos en b(una instancia de B) es lo mismo que usarlos en b.a(la instancia de Aa la que se reenvían).

clase  A :  def  __init__ ( self ,  x )  ->  Ninguno :  self . x  =  x def  foo ( auto ):  imprimir ( auto . x )clase  B :  def  __init__ ( self ,  a )  ->  Ninguno :  self . un  =  un def  foo ( yo ):  yo . a . foo () @property  def  x ( self ):  devuelve  self . a . X @X . definidor  def  x ( self ,  x ):  self . a . x  =  x @X . eliminar  def  x ( self ):  del  self . a . Xa  =  A ( 42 ) b  =  B ( a ) b . foo ()  # Imprime '42'. b . x  # Tiene valor '42' b . x  =  17  # bax ahora tiene el valor 17 del  b . x  # Elimina bax

Simple

Diagrama de clases UML que ilustra el reenvío.
Diagrama de clases UML que ilustra el reenvío.

En este ejemplo de Java , la Printer clase tiene un printmétodo. Este método de impresión, en lugar de realizar la impresión en sí, reenvía a un objeto de clase RealPrinter. Para el mundo exterior parece que el Printerobjeto está haciendo la impresión, pero el RealPrinterobjeto es el que realmente hace el trabajo.

Reenviar es simplemente pasar un deber a alguien/algo más. Aquí hay un ejemplo simple:

class  RealPrinter { // el "receptor" void print () { System . afuera . println ( "¡Hola mundo!" ); } }         class  Impresora { // la RealPrinter "remitente" p = nueva RealPrinter (); // crea el receptor void print () { p . imprimir (); // llama al receptor } } public class Main { public static void main ( String [] argumentos ) { // para el mundo exterior parece que la impresora realmente imprime. Impresora impresora = nueva Impresora (); impresora . imprimir (); } }                                

Complejo

El caso más complejo es un Patrón Decorador que mediante el uso de interfaces , el reenvío puede hacerse más flexible y seguro . "Flexibilidad" aquí significa que Cno es necesario hacer referencia a él Ao Bde ninguna manera, ya que se abstrae el cambio de reenvío C. En este ejemplo, la clase Cpuede reenviar a cualquier clase que implemente una interfaz I. La clase Ctiene un método para cambiar a otro reenviador. Incluir las implementscláusulas mejora la seguridad de tipos , porque cada clase debe implementar los métodos en la interfaz. La principal desventaja es más código.

interfaz  I { void f (); vacío g (); } clase A implementa I { public void f () { System . afuera . println ( "A: haciendo f()" ); } public void g () { Sistema . afuera . println ( "A: haciendo g()" ); } } clase B implementa I { public void f () { System . afuera . println ( "B: haciendo f()" ); } public void g () { Sistema . afuera . println ( "B: haciendo g()" ); } } // cambiando el objeto de implementación en tiempo de ejecución (normalmente hecho en tiempo de compilación) clase C implementa I { I i = null ; // reenvío público C ( I i ){ setI ( i ); } público vacío f () { i . f (); } public void g () { i . gramo (); } // atributos normales public void setI ( I i ) { this . yo = yo ; } } public class Main { public static void main ( String [] argumentos ) { C c = new C ( new A ()); C . f (); // salida: A: haciendo f() c . gramo (); // salida: A: haciendo g() c . establecerI ( nuevo B ()); C . F                                                                               (); // salida: B: haciendo f() c . gramo (); // salida: B: haciendo g() } }

Aplicaciones

El reenvío se utiliza en muchos patrones de diseño. [2] El reenvío se utiliza directamente en varios patrones:

El reenvío se puede utilizar en otros patrones, pero a menudo se modifica su uso; por ejemplo, una llamada a un método en un objeto da como resultado que se llamen a varios métodos diferentes en otro:

Referencias

  1. ^ abc Büchi, Martín; Weck, Wolfgang (2000). "Envoltorios genéricos" (PDF) . ECOOP 2000 — Programación orientada a objetos . Apuntes de conferencias sobre informática. vol. 1850, págs. 212-213. doi :10.1007/3-540-45102-1_10. ISBN 978-3-540-67660-7.
  2. ^ Gama, Erich ; Timón, Richard ; Johnson, Ralph ; Vlissides, John (1995). Patrones de diseño: elementos de software reutilizable orientado a objetos . Addison-Wesley . Código Bib : 1995dper.book.......G. ISBN 978-0-201-63361-0.