Double Dispatching

Double Dispatching es una forma "elegante" de romper el polimorfismo.

La idea basica de objetos es que si vos haces una jerarquia de clases, no te preocupes exactamente por cual subclase del objeto que estas usando. Por ejemplo, supongamos que estamos haciendo el diseño de clases de un Juego en donde hay varios jugadores y varios enemigos. Los jugadores son los Moviles controlador por personas, y los Enemigos son los que controla la computadora. Ademas en el juego puede haber varias instancias de cada clase. Varios enemigos luchando contra varios jugadores. Si tenes dos clases llamadas Jugador y Enemigo que ambas cuelgan de "Movil", puedas hacer algo asi:

PHP:
  1. $posicion = $this->darPosicionAtaque();
  2. $unMovil = $mapa->darMovilEn( $posicion );
  3.  
  4. // Aca esta el dilema ...
  5. $unMovil->atacar( $this );

Yo ataco a un Movil. El que llama a "atacar" no le interesa saber "$movil" de que clase es. El tema es que, a veces, necesitas saberlo para poder calcular las ecuaciones de golpe entre cada uno, o si dos jugadores se atacan entre si poder realizar las penalizaciones en caso de tener friendly-fire. Una opcion es preguntar por la clase del objeto, pero eso rompe con todo lo que la POO intenta hacer de diferente con los lenguajes procedurales / estructurados.

En cambio, la idea del D.D. es aprovechar que las clases saben realmente quien son. Si tenes una clase Enemigo, entonces toda funcion de esa clase sabe que realemnte uno mismo es un Enemigo. Entonces haces algo asi:

PHP:
  1. class Movil {
  2.  
  3.  // aca no va ningun codigo interesante ...
  4.  
  5.  // Yo ataco al argumento
  6.  public function atacar( $atacado );
  7.  
  8.  // El argumento me ataca
  9.  public function atacadoPorJugador( $atacante );
  10.  public function atacadoPorEnemigo( $atacante );
  11. }
  12.  
  13. class Jugador {
  14.  public atacar( $atacado ) {
  15.   $atacado->atacadoPorJugador( $this );
  16.  }
  17.  public function atacadoPorJugador( $atacante ) {
  18.   echo "Soy un Jugador y me ataca un Jugador";
  19.  }
  20.  public function atacadoPorEnemigo( $atacante ) {
  21.   echo "Soy un Jugador y me ataca un Enemigo";
  22.  }
  23. }
  24.  
  25. class Enemigo {
  26.  public atacar( $atacado ) {
  27.   $atacado->atacadoPorEnemigo( $this );
  28.  }
  29.  public function atacadoPorJugador( $atacante ) {
  30.   echo "Soy un Enemigo y me ataca un Jugador";
  31.  }
  32.  public function atacadoPorEnemigo( $atacante ) {
  33.   echo "Soy un Enemigo y me ataca un Enemigo";
  34.  }
  35. }

Por cada subclase de Movil que agregues tenes que agregar una funcion nueva a cada subclase existente. Si tenes pocas clases no hay mucho problema, pero si tenes 10 clases, tenes que agregar 100 funciones: es el precio que hay que pagar por no hacer:

PHP:
  1. if ( class_name( $movil ) == "...") { ... }

Dependiendo del caso, esas 100 funciones son preferibles a los horrorosos if que pueden llegar a aparecer.

4 Responses to “Double Dispatching”

  1. Gorlok Says:

    Muy buen artículo.

    A este patrón se lo llama también Visitor. En http://es.wikipedia.org/wiki/Visitor_(patr%C3%B3n_de_dise%C3%B1o) hay más info, aunque en la versión es inglés de la misma página está mejor explicado: http://en.wikipedia.org/wiki/Visitor_pattern

    En la wikipedia hay mucha información con ejemplos sobre los patrones más conocidos. Al pie de dichas páginas, hay un índice de patrones muy interesante.

    Ahora, hablando de este patrón, si bien a veces es la mejor opción, le tengo bastante rechazo ^^ porque hay que escribir N^2 métodos si hay N clases, y es muy sucio tener que modificar todas las clases existentes cada vez que se agrega una nueva.

    En performance es muy eficiente. Se usa mucho en parsers y cosas así. Pero lo que se gana en performance, se pierde en limpieza de diseño y mantenimiento, que como dije, al crecer el número de clases, se hace inviable.

    Otra alternativa, más complicada, es combinar inversión de control por inyección de código, como se hace con un patrón Command, y un solo método de “ataque” (siguiendo con el ejemplo) al cual se puedan subscribir commands como en el patrón Observer (para subscribir nuevos comandos en la clase, que serán seleccionados usando una hash o tabla indexada por clases). Tendría que armar un ejemplo para explicarlo mejor, pero lo dejaré como tarea para el lector :P

    Hay más sobre técnicas de este estilo en http://www.martinfowler.com/articles/injection.html

    Saludos,
    Gorlok

  2. RJG Says:

    Excelente artículo Alejandro, más claro no lo podrías haber explicado.
    De todas formas… ¿Se utiliza DD en implementaciones reales? Yo pensaba que era sólo para aprobar Objetos I ;P

  3. Tano Says:

    Siempre los ejemplos de double dispatching se basan en competencias, algun juego jeje. Pero se entiende.
    Mira comento.
    A medida que avanzan los años cada vez da mas miedo escribir un if…. (habria que sacarlos? jeje)

    Saludoss!!

  4. Blog de Alejo » Blog Archive » Programacion Orientada a Objetos III: A ver, clase… Says:

    [...] Ya les hablé de Poo, Más Poo, Double Dispatching. [...]

Leave a Reply

Powered by WP Hashcash