Delegación | |
---|---|
delegación | |
Descrito en Patrones de diseño | No |
La delegación es un patrón de diseño básico en el que un objeto expresa externamente algún comportamiento , pero en realidad transfiere la responsabilidad de realizar este comportamiento a un objeto relacionado. El patrón de delegación es la abstracción fundamental sobre la cual se implementan los otros patrones: composición (también llamada agregación), mixins y aspectos .
La capacidad de cambiar el comportamiento de una instancia particular de un objeto en lugar de crear una nueva clase a través de la herencia.
Este patrón generalmente dificulta la optimización de la velocidad a favor de una pureza de abstracción mejorada.
Si bien la delegación no es compatible con el lenguaje Java, es compatible con muchos entornos de desarrollo [1] .
En este ejemplo de Java , la clase Btiene un método auxiliar que pasa métodos al . La clase pretende tener atributos de clase . foo()bar()ABA
Texto fuente en java clase A { void foo () { Sistema . fuera _ println ( "A: metodo foo() llamado" ); } barra vacía () { Sistema . fuera _ println ( "A: barra de método() llamada" ); } } class B { // Crea un objeto cuyos métodos delegarán el comportamiento. A a = nuevo A (); vacío foo () { un . foo (); } barra vacía () { a . barra (); } } public class Main { public static void main ( String [] args ) { B b = new B (); segundo _ foo (); segundo _ barra (); } } Ejemplo complejoUsando interfaces , la delegación se puede hacer de una manera más flexible y segura . En este ejemplo, la clase Cpuede delegar Aen B. La clase Ctiene métodos para cambiar entre clases Ay B. Incluir la extensión implements mejora la seguridad de tipos porque cada clase debe implementar los métodos en la interfaz. La principal desventaja es más código.
Tomemos un ejemplo. Suponga que necesita implementar un temporizador de tal manera que se llame a alguna función después de una cierta cantidad de tiempo. El programador de temporizadores quiere proporcionar una asignación de función a los usuarios de su clase (otros programadores).
Texto fuente en java /** * La interfaz describe la acción que se llamará cuando ocurra el evento * del temporizador. */ interfaz TimerAction { void onTime (); } class WakeUpAction implementa TimerAction { @Override public void onTime () { System . fuera _ println ( "¡Hora de levantarse!" ); } } class ChickenIsReadyAction implementa TimerAction { @Override public void onTime () { System . fuera _ println ( "¡El pollo está listo!" ); } } /** * Clase de temporizador. Bajo ciertas condiciones, se llama a TimerAction. */ class Timer { acción TimerAction ; /** * Una función que el programador llama para configurar la hora. */ void ejecutar () { if ( isTime ()) { acción . a la hora (); } } /** * Alguna función que se ocupa de todo el trabajo del tiempo. Su * implementación no es interesante en este contexto. * * @return */ private boolean isTime () { return true ; } public static void main ( String [] args ) { sistema _ fuera _ println ( "Ingrese el tipo de acción:" ); Escáner escáner = nuevo Escáner ( System . in ); Cadena actionType = escáner . siguienteLinea (); Temporizador temporizador = nuevo temporizador (); if ( actionType . equalsIgnoreCase ( "establecer temporizador de activación" )) { timer . acción = nueva WakeUpAction (); } else if ( actionType . equalsIgnoreCase ( "establecer temporizador de pollo" )) { temporizador . action = new ChickenIsReadyAction (); } temporizador _ ejecutar (); }Este ejemplo es una versión C++ del ejemplo complejo de Java anterior. Dado que C++ no tiene una construcción de interfaz, la clase totalmente abstracta desempeña el mismo papel . Las ventajas y desventajas son básicamente las mismas que en el ejemplo de Java.
Texto fuente en c++ #incluir <iostream> clase I { público : vacío virtual f () = 0 ; vacío virtual g () = 0 ; }; clase A : público I { público : void f () { std :: cout << "A: llamando al método f()" << std :: endl ; } void g () { std :: cout << "A: llamar al método g()" << std :: endl ; } }; clase B : público I { público : void f () { std :: cout << "B: llamar al método f()" << std :: endl ; } void g () { std :: cout << "B: llamar al método g()" << std :: endl ; } }; clase C : público I { público : // Constructor C () : m_i ( nueva A () ) { } // Destructor virtual ~ C () { eliminar m_i ; } vacío f () { m_i -> f (); } vacío g () { m_i -> g (); } // Con estos métodos cambiamos el campo-objeto, cuyos métodos delegaremos void a A () { eliminar m_i ; m_i = nuevoA ( ); } vacío toB () { eliminar m_i ; m_i = nueva B (); } privado : // Declaramos un objeto cuyos métodos delegaremos I * m_i ; }; int principal () { C c ; do . f (); do . gramo (); do . toB (); do . f (); do . gramo (); devolver 0 ; } /* Salida: A: llamar al método f() A: llamar al método g() B: llamar al método f() B: llamar al método g() */Este es un ejemplo de un caso que se encuentra a menudo en la práctica. Hay una tarea para crear una clase para el almacenamiento de la lista de empleados. Los datos de cada empleado se almacenan en un objeto de la clase Empleado. Existe una clase estándar y preparada para almacenar una lista de objetos Employee. Ya ha implementado mecanismos para trabajar con la lista (por ejemplo, asignación de memoria, agregar y quitar de la lista). Heredar la clase de lista de empleados de la clase de lista de objetos no es aceptable aquí, porque obtendremos todos los métodos (incluso aquellos que no nos interesan). Además, tendremos que realizar casting de tipos en algunos casos. La forma más elegante de salir de este caso es delegar algunos de los métodos de la clase de lista de objetos a la clase de lista de empleados. En las reglas OOP, es mejor representar la lista de objetos con un método privado (privado) de la lista de empleados. En este caso, se puede acceder a la lista a través de un indexador.
Texto fuente en C# utilizando el sistema ; usando System.Collections.Generic ; usando System.Linq ; usando System.Text ; namespace Employees { /// <summary> /// Clase para almacenar datos de empleados. /// </summary> class Empleado { private string name ; departamento privado de cuerdas ; empleado público ( cadena nombre , cadena departamento ) { this . nombre = nombre ; esto _ departamento = departamento ; } /// <resumen> /// Nombre del empleado. /// </summary> public string Nombre { get { return this . nombre ; } } /// <resumen> /// Departamento de trabajo. /// </summary> public string Department { get { return this . departamento ; } } } /// <summary> /// Clase para almacenar una lista de empleados. /// </summary> class EmployeesList { lista privada < Empleado > empleados = nueva Lista < Empleado >(); /// <summary> /// Propiedad para obtener y escribir un empleado por índice. /// </summary> /// <param name="index">Índice de empleados.</param> /// <returns>Employee.</returns> public Employee this [ int index ] { get { return employee [ índice ]; } set { empleados [ índice ] = valor ; } } /// <resumen> /// Añadir un nuevo empleado. /// </summary> /// <param name="empleado">Nuevo empleado.</param> public void Add ( Empleado empleado ) { empleados . Añadir ( empleado ); } /// <summary> /// Eliminación de un empleado existente. /// </summary> /// <param name="employee">El empleado a eliminar.</param> public void Eliminar ( Empleado empleado ) { empleados . Quitar ( empleado ); } /// <summary> /// Búsqueda secuencial de un empleado por nombre. /// </summary> /// <param name="name">Nombre del empleado.</param> /// <param name="offset">Posición desde la que empezar a buscar.</param> // / < devuelve>Índice de empleados.</retornos> public int GetIndexOfEmployeeByName ( string name , int offset = 0 ) { for ( int i = offset ; i < empleados . Contar ; i ++) { if ( empleados [ i ]. Nombre == nombre ) { retornar i ; } } retorno - 1 ; } } class Program { static void Main ( string [] args ) { //Crear una lista de empleados y agregarle entradas EmployeesList empList = new EmployeesList (); empList . Agregar ( nuevo empleado ( "Shlensky Dmitry" , "estudio web" )); empList . Agregar ( nuevo Empleado ( "Kusy Nazar" , "estudio web" )); empList . Agregar ( nuevo empleado ( "Urraca Orest" , "estudio web" )); //Buscar al empleado Kusyi Nazar y mostrar el resultado al buscar desde el principio y desde la 2ª posición Consola . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" ). ToString ()); consola _ WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" , 2 ). ToString ()); //Buscar y eliminar empleado Soroka Orestes empList . Remove ( empList [ empList . GetIndexOfEmployeeByName ( "Urraca Orestes" )]); } } } Texto fuente en C# 2 utilizando el sistema ; usando System.Collections.Generic ; usando System.Linq ; usando System.Text ; namespace Employees { /// <summary> /// Clase para almacenar datos de empleados. /// </summary> class Empleado { private string name ; departamento privado de cuerdas ; empleado público ( cadena nombre , cadena departamento ) { this . nombre = nombre ; esto _ departamento = departamento ; } /// <resumen> /// Nombre del empleado. /// </summary> public string Nombre { get { return this . nombre ; } } /// <resumen> /// Departamento de trabajo. /// </summary> public string Department { get { return this . departamento ; } } } /// <summary> /// Clase para almacenar una lista de empleados. /// </summary> class EmployeesList { lista privada < Empleado > empleados = nueva Lista < Empleado >(); /// <summary> /// Propiedad para obtener y escribir un empleado por índice. /// </summary> /// <param name="index">Índice de empleados.</param> /// <returns>Employee.</returns> public Employee this [ int index ] { get { return employee [ índice ]; } set { empleados [ índice ] = valor ; } } /// <summary> /// Propiedad para obtener y escribir un empleado por nombre. /// </summary> /// <param name="name">Nombre del empleado.</param> /// <returns>El primer empleado cuyo nombre coincidió o fue nulo</returns> public Employee this [ string name ] { obtener { foreach ( artículo de empleado en empleados ) { si ( artículo . Nombre == nombre ) devolver artículo ; } devuelve nulo ; } } /// <resumen> /// Añadir un nuevo empleado. /// </summary> /// <param name="empleado">Nuevo empleado.</param> public void Add ( Empleado empleado ) { empleados . Añadir ( empleado ); } /// <summary> /// Eliminación de un empleado existente. /// </summary> /// <param name="employee">El empleado a eliminar.</param> public void Eliminar ( Empleado empleado ) { empleados . Quitar ( empleado ); } /// <summary> /// Búsqueda secuencial de un empleado por nombre. /// </summary> /// <param name="name">Nombre del empleado.</param> /// <param name="offset">Posición desde la que empezar a buscar.</param> // / < devuelve>Índice de empleados.</retornos> public int GetIndexOfEmployeeByName ( string name , int offset ) { int index = - 1 ; for ( int i = compensación ; i < empleados . Cuenta ; i ++) { if ( empleados [ i ]. Nombre == nombre ) { index = i ; romper ; } } índice de retorno ; } /// <summary> /// Búsqueda secuencial de un empleado por nombre. /// </summary> /// <param name="name">Nombre del empleado.</param> /// <returns>Índice de empleados.</returns> public int GetIndexOfEmployeeByName ( string name ) { return GetIndexOfEmployeeByName ( name , 0 ); } } class Program { static void Main ( string [] args ) { //Crear una lista de empleados y agregarle entradas EmployeesList empList = new EmployeesList (); empList . Agregar ( nuevo empleado ( "Shlensky Dmitry" , "estudio web" )); empList . Agregar ( nuevo Empleado ( "Kusy Nazar" , "estudio web" )); empList . Agregar ( nuevo empleado ( "Urraca Orest" , "estudio web" )); //Buscar al empleado Kusyi Nazar y mostrar el resultado al buscar desde el principio y desde la 2ª posición Consola . WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" ). ToString ()); consola _ WriteLine ( empList . GetIndexOfEmployeeByName ( "Kusy Nazar" , 2 ). ToString ()); //Buscar y eliminar empleado Soroka Orestes empList . Quitar ( empList [ "Urraca Orestes" ]); } } }Este ejemplo es una versión de Object Pascal del ejemplo no trivial anterior.
Texto fuente en Object Pascal unidad UnidadEmpleadores ; interfaz utiliza Contnrs ; type // Clase para almacenar datos de empleados TEmployee = class private FName : string ; FDepartamento : cadena ; constructor público Crear ( Nombre , Departamento : cadena ) ; propiedad publicada Nombre : string read FName ; propiedad Departamento : la cadena lee FDepartamento ; fin ; // Clase para almacenar la lista de empleados TEmployeersList = class private // Objeto de la clase "lista de objetos" FEmployeersList : TObjectList ; function GetEmployee ( Índice : Integer ) : TEmployee ; procedimiento SetEmployee ( índice : entero ; valor const : TEmployee ) ; constructor público Crear ; destructor Destruir ; anular ; Función Añadir ( Empleado : TEmployee ) : Entero ; procedimiento Quitar ( Empleado : TEmployee ) ; función IndexEmployeeByName ( Nombre : cadena ; Desplazamiento : Entero = 0 ) : Entero ; propiedad Empleados [ Índice : Integer ] : TEmployee read GetEmployee write SetEmployee ; predeterminado ; fin ; implementación {empleado} constructor TEmpleado . Crear ( Nombre , Departamento : cadena ) ; comenzar FName := Nombre ; FDepartamento := Departamento ; fin ; { TemployeersList } constructor TEmployeersList . crear ; begin // Crea un objeto cuyos métodos delegaremos FEmployeersList := TObjectList . crear ; fin ; destructor TEmployeersList . destruir ; comenzar FEmployersList . Gratis ; heredado ; fin ; función TemployeersList . GetEmployee ( Índice : Integer ) : TEmployee ; comenzar el resultado : = FEmployeersList [ Índice ] como TEmployee ; fin ; procedimiento TEmployeersList . SetEmployee ( Índice : Entero ; Valor const : TEmployee ) ; comenzar FEmployeersList [ Índice ] := Valor ; fin ; función TemployeersList . IndexEmployeeByName ( Nombre : cadena ; Desplazamiento : Entero = 0 ) : Entero ; // Búsqueda secuencial de un empleado por nombre // A través del argumento Offset, puede establecer la posición desde la que buscar. // Si no se encuentra el empleado, devolverá un valor menor que cero (-1) var Index : Integer ; comenzar Resultado := - 1 ; // Asumiendo que no está en la lista de Index := FEmployeersList . Count - 1 downto Offset do if ( FEmployeeList [ Índice ] as TEmployee ) . Nombre = Nombre y luego comenzar Resultado : = Índice ; salida ; fin ; fin ; función TemployeersList . Añadir ( Empleado : TEmployee ) : Entero ; comenzar Resultado := FEmployeersList . Añadir ( Empleado ) ; fin ; procedimiento TEmployeersList . Quitar ( Empleado : TEmployee ) ; comenzar FEmployersList . Quitar ( Empleado ) ; fin ; fin _Desafortunadamente, no todos los programadores usan el patrón de delegación. Por ejemplo, Borland (el desarrollador del entorno de programación Delphi ) en su biblioteca de clases estándar heredó la clase de lista de objetos TObjectList antes mencionada de la clase de lista de punteros TList . Esto causó descontento entre algunos programadores experimentados.
Este ejemplo es una versión PHP del ejemplo simple de Java anterior.
código fuente PHP5 <?php clase A { public function f () { print "A: Llame al método f()<br />" ; } public function g () { print "A: Llamamos al método g()<br />" ; } } clase C { privado $_a ; public function __construct () { $this -> _a = new A ; } función pública f () { $esto -> _a -> f (); } función pública g () { $esto -> _a -> g (); } public function y () { print "C: llamar al método y()<br />" ; } } $obj = nueva C ; $objeto -> f (); $objeto -> g (); $objeto -> y (); ?> Ejemplo complejoEste ejemplo es una versión PHP del ejemplo complejo de Java anterior.
código fuente PHP5 <?php // usar interfaz para tipo interfaz de seguridad I { public function f (); función pública g (); } la clase A implementa I { public function f () { print "A: Call f()<br />" ; } public function g () { print "A: Llamamos al método g()<br />" ; } } la clase B implementa I { public function f () { print "B: Call f()<br />" ; } public function g () { print "B: Llamar al método g()<br />" ; } } la clase C implementa I { private $_i ; // crea un objeto cuyos métodos serán delegados public function __construct () { $this -> _i = new A ; } // con estos metodos cambiamos el campo-objeto, cuyos metodos delegaremos public function aA () { $this -> _i = new A ; } public function toB () { $this -> _i = new B ; } // métodos delegados public function f () { $this -> _i -> f (); } función pública g () { $esto -> _i -> g (); } } $obj = nueva C ; $objeto -> f (); $objeto -> g (); $objeto -> toB (); $objeto -> f (); $objeto -> g (); ?> Ejemplo no trivialEste ejemplo es una versión PHP del ejemplo no trivial anterior.
código fuente PHP5 <?php // clase para almacenar datos de empleados clase Empleado { privado $_nombre ; privado $_departamento ; public function __construct ( $nombre , $departamento ) { $esto -> _nombre = $nombre ; $esto -> _departamento = $departamento ; } public function getName () { return $this -> _name ; } public function obtenerDepartamento () { return $this -> _departamento ; } } // clase para almacenar una lista de objetos class ObjectList { privado $_objList ; public function __construct () { $this -> free (); } /** *¡para no aburrirse! */ public function free () { $this -> _objList = array (); } public function count () { return count ( $this -> _objList ); } función pública añadir ( $obj ) { array_push ( $this -> _objList , $obj ); } función pública remove ( $obj ) { $k = array_search ( $obj , $this -> _objList , true ); if ( $k !== false ) { unset ( $this -> _objList [ $k ] ); } } public function get ( $index ) { return $this -> _objList [ $index ]; } conjunto de funciones públicas ( $index , $obj ) { $this -> _objList [ $index ] = $obj ; } } // clase para almacenar empleados class EmployeeList { // objeto de la clase "lista de objetos" private $_employeersList ; public function __construct (){ // crea un objeto cuyos métodos delegaremos $this -> _employeersList = new ObjectList ; } función pública getEmployer ( $index ) { return $this -> _employeersList -> get ( $index ); } public function setEmployer ( $index , Employee $objEmployer ) { $this -> _employeersList -> set ( $index , $objEmployer ); } public function __destruct () { $this -> _employeersList -> free (); } public function add ( Empleado $objEmployer ) { $this -> _employeersList -> add ( $objEmployer ); } quitar función pública ( Empleado $objEmployer ) { $this -> _employeersList -> remove ( $objEmployer ); } // búsqueda secuencial de un empleado por nombre // a través del argumento $offset, puede establecer la posición desde la cual buscar. // si no se encuentra el empleado, devolverá un valor menor que cero (-1) public function getIndexByName ( $name , $offset = 0 ) { $result = - 1 ; // asume que no está en la lista $cnt = $this -> _employeersList -> count (); for ( $i = $compensación ; $i < $cnt ; $i ++ ) { if ( ! strcmp ( $nombre , $this -> _employeersList -> get ( $i ) -> getName () ) ) { $resultado = $i ; romper ; } } devuelve $resultado ; } } $obj1 = nuevo empleado ( "Tanasiychuk Stepan" , "estudio web" ); $obj2 = nuevo empleado ( "Kusy Nazar" , "estudio web" ); $obj3 = nuevo empleado ( "Urraca Orest" , "estudio web" ); $objList = new EmployeeList (); $objList -> agregar ( $obj1 ); $objList -> agregar ( $obj2 ); $objList -> agregar ( $obj3 ); echo "<pre>" ; print_r ( $objList ); echo "<hr>" ; $index = $objList -> getIndexByName ( "Kusy Nazar" ); $obj4 = $objList -> getEmployer ( $index ); imprimir_r ( $obj4 ) ; echo "<hr>" ; $objList -> setEmployer ( 2 , $obj4 ); print_r ( $objList ); eco "</pre>" ; ?>Código fuente en Python
#codificación: utf-8 #python 3 clase A : def f ( self ): print ( 'A: llamando al método f' ) def g ( self ): print ( 'A: llamando al método g' ) class C : def __init__ ( uno mismo ): uno mismo . A = A () def f ( self ): devuelve self . A._ _ f () def g ( auto ): devuelve auto . A._ _ gramo () do = do () do . f () #A: llama al método f c . g () #A: método de llamada gPatrones de diseño | |
---|---|
Principal | |
Generativo | |
Estructural | |
conductual | |
Programación en paralelo |
|
arquitectónico |
|
Plantillas Java EE | |
Otras plantillas | |
Libros | |
Alusiones personales |