pattern examples design-patterns visitor double-dispatch

design-patterns - examples - java visitor pattern



Diferencia entre el patrĂ³n de visitante y el doble despacho (5)

Estoy leyendo sobre el patrón de visitante, y parece lo mismo que Double Dispatch. Hay alguna diferencia entre los dos. ¿Los dos términos significan lo mismo?

referencia: http://www.vincehuston.org/dp/visitor.html


En breve

provienen de diferentes conceptualizaciones que, en algunos idiomas en los que el doble despacho no se admite de forma nativa, conducen al patrón de visitantes como una forma de concatenar dos (o más) despachos únicos para tener un sustituto de múltiples despachos.

En largo

La idea del envío múltiple es, esencialmente, permitir una llamada como

void fn(virtual base_a*, virtual base_b*); (nota: no como miembro de la clase: ¡esto NO es C ++!)

eso puede ser anulado como

void fn(virtual derived_a1*, virtual derived_b1*); void fn(virtual derived_a2*, virtual derived_b1*); void fn(virtual derived_a1*, virtual derived_b2*); void fn(virtual derived_a2*, virtual derived_b2*);

para que, al llamar

fn(pa, pb)

la llamada se redirige a la anulación que coincide con el tipo de tiempo de ejecución real de pa y pb . (Puede generalizar esto a cualquier cantidad de parámetros)

En lenguaje como C ++, C #, Java, este mecanismo no existe y el despacho de tipo de tiempo de ejecución funciona básicamente con un solo parámetro (que, al ser solo uno, se hace implícito en la función al hacer que la función sea miembro de la clase:

en otras palabras, el pseudocódigo

void fn(virtual base_a*, base_b*)

se convierte en (C ++ real)

class base_a { public: virtual void fn(base_b*); }

Tenga en cuenta que aquí no hay más virtual frente a base_b , que a partir de ahora es estático. Una llamada como

pa->fn(pb) si pa apunta a un derivado_a2 y pb a un derivado_b1 se enviará a derivado_a2 :: fn (base_b *), sin importar si hay un derivado_a2 :: fn (derivado_b1 *) allí: la ejecución el tipo de tiempo del objeto señalado por pb no se tiene en cuenta.

La idea del patrón de visitante es que llame al despacho virtual de un objeto que llama (eventualmente respalda) el despacho virtual de otro:

class base_a { public: virtual void fn(base_b*)=0; virtual void on_visit(derived_b1*)=0; virtual void on_visit(derived_b2*)=0; }; class base_b { public: virtual void on_call(derived_a1*)=0; virtual void on_call(derived_a2*)=0; }; //forward declarations, to allow pointers free use in other decls. class derived_a1; class derived_b1; class derived_a1: public base_a { public: virtual void fn(base_b* pb) { pb->on_call(this); } virtual void on_visit(derived_b1* p1) { /* useful stuff */ } ... }; class derived_b1: public base_b { public: virtual void on_call(derived_a1* pa1) { pa1->on_visit(this); } ... };

ahora, una llamada como pa->fn(pb) , si pa apunta a derived_a1 y pb a derived_b1, finalmente irá a derived_a1::on_visit(derived_b1*) .


De la Wikipedia :

el patrón de visitante simula el despacho doble en un lenguaje convencional orientado a objetos de un solo envío, como Java, Smalltalk y C ++.

También de Wikipedia :

El problema descrito anteriormente puede resolverse simulando el envío doble, por ejemplo, utilizando un patrón de visitante.


El envío doble es un problema técnico que, dependiendo del idioma, se puede resolver de diferentes maneras: algunos idiomas admiten el doble despacho directamente. El patrón de visitante es un patrón que se puede usar para resolver diferentes problemas. En el caso de C ++, es la solución más frecuente (pero no la única) utilizada para el doble despacho, pero no se usa exclusivamente para eso, y puede ser útil incluso en idiomas que admiten doble despacho.


El patrón de visitante es una solución que implementa el comportamiento de doble envío. Puede haber muchas otras soluciones también. El término doble despacho en sí mismo no da ninguna idea de solución, de hecho es un problema cuya solución es provista por un patrón de visitante .

En C # (4.0), se podría usar dynamic palabra clave dynamic para implementar el despacho doble, en cuyo caso no se requiere un patrón de visitante. Aquí está mi solución al problema del doble despacho usando palabra clave dynamic :


El Despacho dinámico se refiere al concepto de envío a un método basado en la información de tiempo de ejecución, en general. La mayoría de los sistemas OO (como en Java / C # / C ++) generalmente implementan el despacho dinámico a través de métodos virtual (independientemente de si todos los métodos son virtuales o no dependen del idioma); esto los restringe a despachar según un único argumento de método (la referencia de objeto implícita).

En general, puede desear despachar según una cantidad arbitraria de elementos. Double Dispatch, por ejemplo, es el requisito / capacidad para despachar según dos argumentos del método.

Por otro lado, Visitor Pattern es una implementación de Multi Dispatch en general y, por lo tanto, Double Dispatch en particular en dichos sistemas OO.