Ir al contenido

Delegation (patrón de diseño)

De Wikipedia, la enciclopedia libre
Esta es una versión antigua de esta página, editada a las 16:21 21 ago 2014 por Vichock (discusión · contribs.). La dirección URL es un enlace permanente a esta versión, que puede ser diferente de la versión actual.

En Ingeniería de software, el patrón de diseño de delegación es una técnica en la que un objeto de cara al exterior expresa cierto comportamiento pero en realidad delega la responsabilidad de implementar dicho comportamiento a un objeto asociado en una relación inversa de responsabilidad.

El patrón de diseño de Delegación es la abstracción fundamental que da soporte a la composición (también referida como agregación), los mixin y los aspectos.

Ejemplos

Ejemplo simple en Java

En este ejemplo realizado en el lenguaje de programación Java, la clase C tiene métodos "cabecera" (método stub) que realizan llamadas a los métodos f() y g() de la clase A

 class A {
     void f() { System.out.println("A: haciendo f()"); }
     void g() { System.out.println("A: haciendo g()"); }
 }
 
 class C {
     // objeto asociado para delegacion
     A a = new A();
 
     void f() { a.f(); }
     void g() { a.g(); }
 
     // atributos normales
     X x = new X();
     void y() { /* haz algo */ }
 }
 
 public class Main {
     public static void main(String[] args) {
         C c = new C();
         c.f();
         c.g();
     }
 }

Ejemplo complejo en Java

Utilizando interfaces Java, la delegación puede hacerse de manera más flexible y fuertemente tipada. En este ejemplo, la clase C puede delegar bien en la clase A o en la clase B. La clase C tiene métodos para conmutar entre las clases A y B. Utilizando la cláusula implements se asegura la fortaleza de tipos porque cada clase debe implementar los métodos definidos en la interfaz. La principal contrapartida es que se añade más código.

 interface I {
     void f();
     void g();
 }
 
 class A implements I {
     public void f() { System.out.println("A: haciendo f()"); }
     public void g() { System.out.println("A: haciendo g()"); }
 }
 
 class B implements I {
     public void f() { System.out.println("B: haciendo f()"); }
     public void g() { System.out.println("B: haciendo g()"); }
 }
 
 class C implements I {
     // objeto asociado de delegacion
     I i = new A();
 
     public void f() { i.f(); }
     public void g() { i.g(); }
 
     // atributos normales
     void toA() { i = new A(); }
     void toB() { i = new B(); }
 }
 
 public class Main {
     public static void main(String[] args) {
         C c = new C();
         c.f();
         c.g();
         c.toB();
         c.f();
         c.g();
     }
 }

Ejemplo complejo en C++

Este ejemplo es una versión en C++ del ejemplo complejo escrito en Java anterior. Puesto que C++ no tiene interfaces propiamente dichas, una clase abstracta realiza el mismo juego. Las ventajas y desventajas son principalmente las mismas que en el ejemplo en Java.

 #include <iostream>
 using namespace std;
 
 interface I {
   public:
     virtual void f() = 0;
     virtual void g() = 0;
     virtual ~I() {}
 };
 
 class A : public I {
   public:
     void f() { cout << "A: haciendo f()" << endl; }
     void g() { cout << "A: haciendo g()" << endl; }
     ~A() { cout << "A: llamada al destructor." << endl; }
 };
 
 class B : public I {
   public:
     void f() { cout << "B: haciendo f()" << endl; }
     void g() { cout << "B: haciendo g()" << endl; }
     ~B() { cout << "B: llamada al destructor." << endl; }
 };
 
 class C : public I {
   public:
     // constructor/destructor
     C() : i( new A() ) { }
     virtual ~C() { delete i; }
 
   private:
     // Interfaz de delegacion
     I* i;
 
   public:
     void f() { i->f(); }
     void g() { i->g(); }
 
     // atributos normales
     void toA() { delete i; i = new A(); }
     void toB() { delete i; i = new B(); }
 };
 
 int main() {
     C* c = new C();
 
     c->f();
     c->g();
     c->toB();
     c->f();
     c->g();
 }