Articulo de referencia

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 real del miembro...

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 real 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 con frecuencia objeto contenedor y los miembros de reenvío explícitos se denominan funciones contenedoras .

Delegación

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

La diferencia entre el reenvío y la delegación es la vinculación del parámetro self en el contenedor 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 contenedor. ... 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 con la herencia "normal". [1]

Por ejemplo, dado el siguiente código:

// Remitente 
void n () { print ( "n1" ); }  
  


// Receptor 
void m () { print ( "m2, " ); n (); }  
  
  


void n () { imprimir ( "n2" ); }  
  

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

En el uso casual, 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 a qué selfse refieren. Mientras que la delegación es análoga a la herencia , permitiendo la reutilización del comportamiento (y concretamente la reutilización de 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 solo del objeto receptor (miembro), no del objeto emisor (original). En ambos casos, la reutilización es dinámica, lo que significa que se determina en tiempo de ejecución (según el objeto al que se delega o reenvía el uso), en lugar de estática, lo que significa que se determina en tiempo de compilación/enlace (según 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 la frágil clase base ; mientras que el reenvío proporciona una encapsulación más fuerte y evita estos problemas; consulte composición sobre herencia . [1]

Ejemplos

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

clase  B { A a ; 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 necesita ser una instancia de A: puede ser una instancia de un subtipo. De hecho, Ani siquiera necesita ser una clase: puede ser una interfaz/ protocolo .

Contrasta con la herencia, en la que foose define en una superclase A(que debe ser una clase, no una interfaz), y cuando se llama en 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 ( self ) 
        : imprimir ( self.x )

clase  B : 
    def  __init __ ( self ,  a )  - >  Ninguno : 
        self.a = a  

    def  foo ( self ) : 
        self.a.foo ( )

    @property 
    def  x ( self ): 
        devuelve  self . a . x

    @x . setter 
    def  x ( self ,  x ): 
        self . a . x  =  x

    @x . deleter 
    def  x ( self ): 
        del  self . a . x

a  =  A ( 42 ) 
b  =  B ( a ) 
b . foo ()   # Imprime '42'. 
b . x   # Tiene el 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 la clase RealPrinter. Para el mundo exterior, parece que el Printerobjeto está realizando la impresión, pero RealPrinteres el objeto el que realmente realiza el trabajo.

Reenviar es simplemente delegar una tarea a alguien o algo más. He aquí un ejemplo sencillo:

clase  RealPrinter { // el " receptor" void print () { System . println ( " ¡Hola mundo!" ); } }  
       
         
    


clase  Printer { // el "remitente" RealPrinter p = new RealPrinter (); // crea el receptor void print () { p.print (); // llama al receptor } } clase pública Main { public static void main ( String [] arguments ) { // para el mundo exterior parece que Printer realmente imprime. Printer printer = new Printer ( ); printer.print () ; } }  
         
      
         
    

 
   
         
        
            
        
    

Complejo

El caso más complejo es un Patrón Decorador que, al usar interfaces , puede hacer que el reenvío sea más flexible y seguro desde el punto de vista de los tipos . "Flexibilidad" aquí significa que Cno es necesario hacer referencia a Ao de ninguna manera, ya que el cambio de reenvío se abstrae de . En este ejemplo, la clase puede reenviar a cualquier clase que implemente una interfaz . La clase tiene un método para cambiar a otro reenviador. Incluir las cláusulas mejora la seguridad de los tipos , porque cada clase debe implementar los métodos en la interfaz. La principal desventaja es más código. BCCICimplements

interfaz  I { void f (); void g (); } clase A implementa I { public void f () { System . out . println ( "A: haciendo f()" ); } public void g () { System . out . println ( "A: haciendo g()" ); } } clase B implementa I { public void f () { System . out . println ( "B: haciendo f()" ); } public void g () { System . out . println ( "B: haciendo g()" ); } } // cambiando el objeto de implementación en tiempo de ejecución (normalmente se hace en tiempo de compilación) clase C implementa I { I i = null ; // reenvío public C ( I i ){ setI ( i ); } public void f () { i . f (); } public void g () { i . g (); } // atributos normales public void setI ( I i ) { this . i = i ; } } clase pública Main { public static void main ( String [] argumentos ) { C c = new C ( new A ()); c . f (); // salida: A: haciendo f() c . g (); // salida: A: haciendo g() c . setI ( new B ()); c . f 
	 
	 

 
    
	     
	     

 
    
	     
	     

 

    
	   
	
	    
	     
	     
 
	
	        

 
   
	     
		     
			
			
		 
		(); // salida: B: haciendo f() c . g (); // 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 la llamada a varios métodos diferentes en otro:

Referencias

  1. ^ abc Büchi, Martin; Weck, Wolfgang (2000). "Generic Wrappers" (PDF) . ECOOP 2000 — Programación orientada a objetos . Apuntes de clase en informática. Vol. 1850. págs. 212-213. doi :10.1007/3-540-45102-1_10. ISBN 978-3-540-67660-7.
  2. ^ Gamma, Erich ; Helm, Richard ; Johnson, Ralph ; Vlissides, John (1995). Patrones de diseño: elementos de software orientado a objetos reutilizable . Addison-Wesley . Bibcode :1995dper.book.....G. ISBN 978-0-201-63361-0.
Obtenido de "https://es.wikipedia.org/w/index.php?title=Reenvío_(programación_orientada_a_objetos)&oldid=1216855120"